diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7c74c50..70f25e8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,9 @@ Contributions via [pull request](https://github.com/WP-for-Church/Sermon-Manager and [bug reports](https://github.com/WP-for-Church/Sermon-Manager/issues) are welcome! Please submit your pull request to the `develop` branch and use the GitHub issue tracker to report issues. +**Note!** If you have detected any security issues, please write an email to nikola@wpforchurch.com. Do not submit it on the +public forum or in a public GitHub issue. + ### Translations Is the plugin not available in your language or are some translations missing? @@ -24,6 +27,8 @@ Create an account on [wordpress.org](wordpress.org) and you can start translatin [Sermon Manager's page](https://translate.wordpress.org/projects/wp-plugins/sermon-manager-for-wordpress). No coding skills are required at all. +(Our integration with GlotPress is still not ready) + # Development The default branch for the Sermon Manager repository on GitHub is **"master"**, while there is another important branch @@ -31,7 +36,8 @@ called **"dev"** (shortened for "develop"). Each of them serves their own purpos ### master branch The **"master"** branch is a stable branch, and gets updated only on releases. Whenever people checkout/download the -**"master"** branch, they get the source code of the latest official release of the Sermon Manager. +**"master"** branch, they get the source code of the latest official release of the Sermon Manager. (same as if they +downloaded the latest version on WordPress) ### dev branch The **"dev"** branch, is where commits during development are integrated into. It is where the WP For Church team @@ -39,9 +45,8 @@ pushes or merges their actual changes together and where contributions from the integrated into the development version of the plugin. Anyone who wish to try the cutting edge version of Sermon Manager can download the develop branch and install it on their website. -(Note: whenever a commit is created on develop branch, a -development zip package is created by WordPress, which can be downloaded from -[here](https://downloads.wordpress.org/plugin/sermon-manager-for-wordpress.zip).) +(Note: whenever a commit is created on develop branch, a development zip package is created by WordPress, which can be +downloaded from [here](https://downloads.wordpress.org/plugin/sermon-manager-for-wordpress.zip).) Pull requests are always merged into the **"dev"** branch. If you are willing to contribute, make sure that you are sending us pull requests against the dev branch but not the *master* branch. @@ -61,17 +66,15 @@ changes easily. #### In short: -- Features get developed on **feature branches**, either in your local repository or pushed to GitHub. Feature branches +- Big features get developed on **feature branches**, either in your local repository or pushed to GitHub. Feature branches can be rebased. - Once ready, **feature branches** are PR'd to **dev**. -- When the WPFC team wants to make a release, **dev** is branched into a **release branch**. Any necessary stabilization -work happens there, including final changes and testing; **dev** is never frozen, and efforts to PR in **feature branches** -should not stop just because a release is happening. -- When a release is made, the **release branch** is pushed to **master** and **master** is tagged at that point. -- If hotfixes need to be made, then they can be made on the **release branch**. Anything that also applies to the -**development branch** is first committed there, then cherry-picked to the **release branch**. The **release branch** -is then pushed to **master** (again), and tagged (again), going from e.g. 2.10.1 to 2.10.2. -- **dev**, **master** and the **release branches** are all protected; no rebasing happens there. - -(Note: Until 2018-01-19, **release branches** were deleted once they were merged into **master**. That was not a smart move, -since it would be hard to create a hotfix once there is a significant progress on **dev**.) +- When the WPFC team wants to make a release, **dev** is branched into a **release branch**. Version gets bumped, necessary +stabilization work happens, including final changes and testing, on that branch. (**dev** is never frozen, and efforts to PR +in **feature branches** should not stop just because a release is happening) +- When a release is ready to be released, the **release branch** is merged into **dev** & **master**, **master** is tagged +at that point. +- If hotfixes need to be made, then a **hotfix branch** is created from **master** and all necessary fixes are applied on it. +After the critical bug has been fixed and version has been bumped, **hotfix branch** is merged into **master** and **dev**, +and **master** is tagged with at that point. +- **dev** and **master** are protected; no rebasing happens there. diff --git a/assets/css/_import-export.css b/assets/css/_import-export.css new file mode 100644 index 0000000..e3298f8 --- /dev/null +++ b/assets/css/_import-export.css @@ -0,0 +1,72 @@ +.wp-list-table { + overflow: hidden; + height: 100%; } + +.plugin-card { + position: relative; } + .plugin-card > h2 { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + z-index: 1; + color: #4a4a4a !important; + margin: 0; + font-size: 1.7rem; + font-weight: 100; + letter-spacing: 2px; + font-family: 'Roboto', sans-serif; + text-transform: uppercase; + opacity: 0; + transition: opacity .2s; + cursor: default; + width: 100%; + text-align: center; } + .plugin-card.not-available:before { + content: ""; + background: repeating-linear-gradient(45deg, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.05) 10px, rgba(0, 0, 0, 0.1) 10px, rgba(0, 0, 0, 0.1) 20px); + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + z-index: 1; } + .plugin-card.not-available:hover > h2 { + opacity: 1; } + .plugin-card.not-available:hover .plugin-card-top { + -webkit-filter: blur(1px); + filter: blur(1px); } + .plugin-card.not-available * { + color: #ccc; } + .plugin-card.not-available .plugin-icon { + filter: opacity(0.2); } + .plugin-card .plugin-card-top { + padding: 0; } + .plugin-card .plugin-card-top:hover .import-note { + display: block; } + .plugin-card .plugin-card-top .import-note { + display: none; + color: rgba(0, 0, 0, 0.5); } + .plugin-card .plugin-card-top .name { + margin-top: 20px; } + .plugin-card .plugin-card-top .desc, .plugin-card .plugin-card-top .name { + margin-left: 185px; } + .plugin-card .plugin-card-top .action-links { + top: 0; } + .plugin-card .plugin-card-top .plugin-icon { + font-size: 5rem; + color: #656565; + left: 0; + top: 0; + height: 168px; + width: 168px; + margin: -20px 20px 0 0; } + .plugin-card .plugin-card-top .plugin-icon.dashicons { + margin-top: 1rem; } + .plugin-card .plugin-card-top .plugin-card-empty-space { + display: inline-block; + width: 1px; + height: 30px; + background: transparent; } + +/*# sourceMappingURL=_import-export.css.map */ diff --git a/assets/css/_import-export.css.map b/assets/css/_import-export.css.map new file mode 100644 index 0000000..7c3f7b5 --- /dev/null +++ b/assets/css/_import-export.css.map @@ -0,0 +1,7 @@ +{ +"version": 3, +"mappings": "AAAA,cAAe;EACb,QAAQ,EAAE,MAAM;EAChB,MAAM,EAAE,IAAI;;AAGd,YAAa;EACX,QAAQ,EAAE,QAAQ;EAElB,iBAAK;IACH,QAAQ,EAAE,QAAQ;IAClB,IAAI,EAAE,GAAG;IACT,GAAG,EAAE,GAAG;IACR,SAAS,EAAE,qBAAqB;IAChC,OAAO,EAAE,CAAC;IACV,KAAK,EAAE,kBAAkB;IACzB,MAAM,EAAE,CAAC;IACT,SAAS,EAAE,MAAM;IACjB,WAAW,EAAE,GAAG;IAChB,cAAc,EAAE,GAAG;IACnB,WAAW,EAAE,oBAAoB;IACjC,cAAc,EAAE,SAAS;IACzB,OAAO,EAAE,CAAC;IACV,UAAU,EAAE,WAAW;IACvB,MAAM,EAAE,OAAO;IACf,KAAK,EAAE,IAAI;IACX,UAAU,EAAE,MAAM;EAIlB,iCAAS;IACP,OAAO,EAAE,EAAE;IACX,UAAU,EAAE,iIAAiI;IAC7I,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,QAAQ;IAClB,IAAI,EAAE,CAAC;IACP,GAAG,EAAE,CAAC;IACN,OAAO,EAAE,CAAC;EAIV,qCAAK;IACH,OAAO,EAAE,CAAC;EAGZ,iDAAiB;IACf,cAAc,EAAE,SAAS;IACzB,MAAM,EAAE,SAAS;EAIrB,4BAAE;IACA,KAAK,EAAE,IAAI;EAGb,uCAAa;IACX,MAAM,EAAE,YAAY;EAIxB,6BAAiB;IACf,OAAO,EAAE,CAAC;IAEV,gDAAqB;MACnB,OAAO,EAAE,KAAK;IAGhB,0CAAa;MACX,OAAO,EAAE,IAAI;MACb,KAAK,EAAE,kBAAkB;IAG3B,mCAAM;MACJ,UAAU,EAAE,IAAI;IAGlB,wEAAa;MACX,WAAW,EAAE,KAAK;IAGpB,2CAAc;MACZ,GAAG,EAAE,CAAC;IAGR,0CAAa;MACX,SAAS,EAAE,IAAI;MACf,KAAK,EAAE,OAAO;MACd,IAAI,EAAE,CAAC;MACP,GAAG,EAAE,CAAC;MACN,MAAM,EAAE,KAAK;MACb,KAAK,EAAE,KAAK;MACZ,MAAM,EAAE,cAAc;MAEtB,oDAAY;QACV,UAAU,EAAE,IAAI;IAIpB,sDAAyB;MACvB,OAAO,EAAE,YAAY;MACrB,KAAK,EAAE,GAAG;MACV,MAAM,EAAE,IAAI;MACZ,UAAU,EAAE,WAAW", +"sources": ["_import-export.scss"], +"names": [], +"file": "_import-export.css" +} \ No newline at end of file diff --git a/assets/css/_import-export.scss b/assets/css/_import-export.scss index 15744d2..d72af0a 100644 --- a/assets/css/_import-export.scss +++ b/assets/css/_import-export.scss @@ -95,5 +95,22 @@ margin-top: 1rem; } } + + .wp-upload-form { + display: none; + } + + .import-sniper { + line-height: 1; + vertical-align: middle; + width: 13px; + display: inline-block; + position: relative; + top: -1px; + display: none; + img { + max-width: 100%; + } + } } } \ No newline at end of file diff --git a/assets/css/admin.css b/assets/css/admin.css index 0ff6b2a..0b49521 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -120,6 +120,18 @@ body.wpfc_sermon_page_sm-import-export .plugin-card { margin: -20px 20px 0 0; } body.wpfc_sermon_page_sm-import-export .plugin-card .plugin-card-top .plugin-icon.dashicons { margin-top: 1rem; } + body.wpfc_sermon_page_sm-import-export .plugin-card .plugin-card-top .wp-upload-form { + display: none; } + body.wpfc_sermon_page_sm-import-export .plugin-card .plugin-card-top .import-sniper { + line-height: 1; + vertical-align: middle; + width: 13px; + display: inline-block; + position: relative; + top: -1px; + display: none; } + body.wpfc_sermon_page_sm-import-export .plugin-card .plugin-card-top .import-sniper img { + max-width: 100%; } body.post-php.post-type-wpfc_sermon #sermon_video_link { width: 25em; } diff --git a/assets/css/admin.css.map b/assets/css/admin.css.map index 70ba3a4..3de082d 100644 --- a/assets/css/admin.css.map +++ b/assets/css/admin.css.map @@ -1,6 +1,6 @@ { "version": 3, -"mappings": "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", +"mappings": "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", "sources": ["_all-sermons.scss","_settings.scss","_import-export.scss","_add-edit-sermon.scss"], "names": [], "file": "admin.css" diff --git a/assets/css/sermon.css b/assets/css/sermon.css index fb2cf11..986a878 100755 --- a/assets/css/sermon.css +++ b/assets/css/sermon.css @@ -320,3 +320,178 @@ h3.wpfc_grid_title a { .wpfc_worship_audio .wp-playlist { border: 0px !important; } + +/******************************* Sermon Sorting *******************************/ +.wpfc-sermon-container #wpfc_sermon_sorting { + padding: 0; + margin: 0 0 48px 0; +} + +.wpfc-sermon-container #wpfc_sermon_sorting form { + margin: 0; +} + +.wpfc-sermon-container #wpfc_sermon_sorting > div { + margin: 0 8px 4px 0; +} + +.wpfc-sermon-container #wpfc_sermon_sorting > div:last-child { + margin: 0 0 4px 0; +} + +@media (max-width: 700px) { + .wpfc-sermon-container #wpfc_sermon_sorting > div { + width: 100%; + margin: 0 0 12px 0; + } + + .wpfc-sermon-container #wpfc_sermon_sorting > div:last-child { + margin: 0; + } +} + +/******************************* Sermon Archive *******************************/ +.wpfc-sermon { + margin-bottom: 48px; +} +.wpfc-sermon:last-child { + margin-bottom: 0; +} +.wpfc-sermon-image { + height: auto; + position: relative; +} +.wpfc-sermon-image-img { + width: 100%; + height: 100%; + background-size: cover; + background-position: center; +} +.wpfc-sermon-inner { + background: white; + border: 1px solid #ddd; +} +.wpfc-sermon.noborder .wpfc-sermon-inner { + border: none; +} + +.wpfc-sermon-main { + padding: 24px; +} + +.wpfc-sermon-meta-item { + font-size: 14px; + opacity: .87; +} + +.wpfc-sermon-meta-series { + margin: 0 0 8px 0; +} + +.wpfc-sermon-title { + margin: 0; + padding: 0; +} + +.wpfc-sermon-meta-date { + margin: 8px 0 0; +} + +.wpfc-sermon-description { + font-size: 14px; + margin: 8px 0 0; +} + +.wpfc-sermon-description p { + margin: 0 0 12px 0; +} + +.wpfc-sermon-description p:last-child { + margin: 0; +} + +.wpfc-sermon-footer { + margin-top: 24px; + padding-top: 24px; + border-top: 1px solid #ddd; +} + +.wpfc-sermon-footer .wpfc-sermon-meta-item { + display: inline-block; + position: relative; +} + +.wpfc-sermon-footer .wpfc-sermon-meta-item:not(:last-child):after { + content: '|'; + padding: 0 4px; + color: #ddd; +} + +/* Horizontal View */ +@media (min-width: 800px) { + .wpfc-sermon-inner { + display: flex; + flex-flow: row wrap; + } + .wpfc-sermon-image { flex: 0 30%; } + .wpfc-sermon-main { flex: 1; } +} + +@media(max-width: 800px) { + .wpfc-sermon-image-img { + padding-top: 56.25%; + } +} + +/******************************* Sermon Singular *******************************/ +.wpfc-sermon-single-image { + margin-bottom: 24px; +} +.wpfc-sermon-single-image img { + display: block; + max-width: 100%; + width: 100%; +} +.wpfc-sermon-single-header, +.wpfc-sermon-single-media { + text-align: center; +} +.wpfc-sermon-single-header .wpfc-sermon-single-meta-item { + font-size: 14px; + opacity: .87; +} +.wpfc-sermon-single-meta-date { + margin-bottom: 8px; +} +.wpfc-sermon-single-title { + margin: 0; + padding: 0; +} +.wpfc-sermon-single-meta { + margin: 8px -8px 0 -8px; +} +.wpfc-sermon-single-meta-item { + display: inline-block; + margin: 0 8px; +} +.wpfc-sermon-single-media > div { + margin: 24px 0; +} +.wpfc-sermon-single-description { + margin-top: 24px; +} +.wpfc-sermon-single-description p:first-child { + margin-top: 0; +} +.wpfc-sermon-single-description p:last-child { + margin-bottom: 0; +} +.wpfc-sermon-single-attachments { + background: #efefef; + border: 1px solid #ddd; + padding: 24px; + margin-top: 24px; +} +.wpfc-sermon-single-topics { + margin-top: 24px; +} diff --git a/assets/css/theme-specific/twentrythirteen.css b/assets/css/theme-specific/twentrythirteen.css new file mode 100644 index 0000000..bebb23c --- /dev/null +++ b/assets/css/theme-specific/twentrythirteen.css @@ -0,0 +1,13 @@ +.wpfc-twentythirteen { + margin: 0 auto; + max-width: 604px; + width: 100%; +} + +#wpfc_sermon_sorting { + margin: 40px 0 0 !important; +} + +.wpfc-sermon { + margin: 0; +} diff --git a/assets/css/theme-specific/twentyfifteen.css b/assets/css/theme-specific/twentyfifteen.css new file mode 100644 index 0000000..359f463 --- /dev/null +++ b/assets/css/theme-specific/twentyfifteen.css @@ -0,0 +1,16 @@ +.wpfc-twentyfifteen #wpfc_sermon_sorting { + margin-left: 8.3333%; + margin-right: 8.3333%; +} + +.wpfc-twentyfifteen .wpfc-sermon-single-image { + margin: 0; +} + +.wpfc-twentyfifteen .wpfc-sermon-single-main { + padding: 10%; +} + +.wpfc-twentyfifteen .hentry { + padding-top: 0; +} diff --git a/assets/css/theme-specific/twentyfourteen.css b/assets/css/theme-specific/twentyfourteen.css new file mode 100644 index 0000000..74b74be --- /dev/null +++ b/assets/css/theme-specific/twentyfourteen.css @@ -0,0 +1,22 @@ +#wpfc_sermon_sorting { + margin: 0 auto 48px auto !important; +} + +#wpfc_sermon_sorting, +.wpfc-sermon, +.wpfc-sermon-single { + max-width: 474px !important; +} + +.wpfc-sermon, +.wpfc-sermon-single { + margin: 0 auto; +} + +.wpfc-sermon:last-child { + margin-bottom: 48px; +} + +.full-width .site-content .hentry.has-post-thumbnail:first-child { + margin-top: 0 !important; +} \ No newline at end of file diff --git a/assets/css/theme-specific/twentyseventeen.css b/assets/css/theme-specific/twentyseventeen.css new file mode 100644 index 0000000..0a943a0 --- /dev/null +++ b/assets/css/theme-specific/twentyseventeen.css @@ -0,0 +1,7 @@ +.wpfc-twentyseventeen .archive .site-main > article { + padding: 0; +} + +.wpfc-sermon { + margin: 0; +} \ No newline at end of file diff --git a/assets/js/additional_classes.js b/assets/js/additional_classes.js new file mode 100644 index 0000000..d13843b --- /dev/null +++ b/assets/js/additional_classes.js @@ -0,0 +1,9 @@ +(function () { + var element = document.getElementsByClassName('wpfc-sermon'); + + for (var i = 0; i < element.length; i++) { + if (element[i].offsetWidth > 600) { + element[i].className += " wpfc-sermon-horizontal"; + } + } +})(); diff --git a/assets/js/admin/import-export.js b/assets/js/admin/import-export.js new file mode 100644 index 0000000..ed92d2f --- /dev/null +++ b/assets/js/admin/import-export.js @@ -0,0 +1,16 @@ +jQuery(document).ready(function () { + var smImportForm = jQuery('#sm-import-upload-form'); + if (smImportForm.length) { + var fileField = smImportForm.find('#upload'); + var importTrigger = smImportForm.siblings('#sm-import-trigger'); + var submitButton = smImportForm.find('#submit'); + importTrigger.click(function() { + fileField.click(); + }); + fileField.change(function (){ + importTrigger.find('.import-sniper').css('display', 'inline-block'); + importTrigger.attr('disabled', true); + submitButton.click(); + }); + } +}); \ No newline at end of file diff --git a/assets/js/admin/settings.js b/assets/js/admin/settings.js index 7fb8a30..f05dbc0 100644 --- a/assets/js/admin/settings.js +++ b/assets/js/admin/settings.js @@ -10,7 +10,6 @@ jQuery('#enable_podcast_redirection').change(function () { */ jQuery(document).ready(function () { var check = jQuery('#enable_podcast_redirection'); - if (check.length) { podcast_redirect(check.is(':checked')); } diff --git a/includes/admin/class-sm-admin-import-export.php b/includes/admin/class-sm-admin-import-export.php index 4fe199d..74a550c 100644 --- a/includes/admin/class-sm-admin-import-export.php +++ b/includes/admin/class-sm-admin-import-export.php @@ -14,7 +14,6 @@ class SM_Admin_Import_Export { */ public static function output() { do_action( 'sm_import_export_start' ); - include 'views/html-admin-import-export.php'; } } \ No newline at end of file diff --git a/includes/admin/class-sm-admin-menus.php b/includes/admin/class-sm-admin-menus.php index 0444ee0..a7114ee 100644 --- a/includes/admin/class-sm-admin-menus.php +++ b/includes/admin/class-sm-admin-menus.php @@ -46,6 +46,7 @@ public function settings_page() { * Init the settings page */ public function import_export_page() { + wp_enqueue_script( 'import-export-js', SM_URL . 'assets/js/admin/import-export.js', array(), SM_VERSION ); SM_Admin_Import_Export::output(); } diff --git a/includes/admin/export/class-sm-export-sm.php b/includes/admin/export/class-sm-export-sm.php new file mode 100644 index 0000000..9c6dbc8 --- /dev/null +++ b/includes/admin/export/class-sm-export-sm.php @@ -0,0 +1,519 @@ + 'wpfc_sermon', + 'author' => false, + 'category' => false, + 'start_date' => false, + 'end_date' => false, + 'status' => false, + ); + $args = wp_parse_args($args, $defaults); + + /** + * Fires at the beginning of an export, before any headers are sent. + * + * @since 2.3.0 + * + * @param array $args An array of export arguments. + */ + //do_action( 'export_wp', $args ); + + $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 ( post_type_exists($args['content']) ) { + $ptype = get_post_type_object($args['content']); + if (!$ptype->can_export) + return; + + $where = $wpdb->prepare("{$wpdb->posts}.post_type = %s", $args['content']); + } else { + return; + } + + $where .= " AND {$wpdb->posts}.post_status != 'auto-draft'"; + + + $join = ''; + + // grab a snapshot of post IDs, just in case it changes during the export + $post_ids = apply_filters('export_post_ids', $wpdb->get_col("SELECT ID FROM {$wpdb->posts} $join WHERE $where"), $args); + $post_type_export = apply_filters('export_post_type', 'wpfc_sermon', $args); + + // get the requested terms ready, empty unless posts filtered by category or all content + $cats = $tags = $terms = array(); + $custom_taxonomies = array( + 'wpfc_preacher', + 'wpfc_sermon_series', + 'wpfc_sermon_topics', + 'wpfc_bible_book', + 'wpfc_service_type' + ); + $custom_terms = (array)get_terms($custom_taxonomies, array('get' => 'all')); + + // 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 = '', ']]]]>', $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 list of taxonomy terms, in XML tag format, associated with a post + * + * @since 2.3.0 + */ + function wxr_post_taxonomy($post_id) { + $custom_taxonomies = array( + 'wpfc_preacher', + 'wpfc_sermon_series', + 'wpfc_sermon_topics', + 'wpfc_bible_book', + 'wpfc_service_type' + ); + $terms = wp_get_object_terms( $post_id, $custom_taxonomies ); + + foreach ( (array) $terms as $term ) { + echo "\t\ttaxonomy}\" nicename=\"{$term->slug}\">" . wxr_cdata( $term->name ) . "\n"; + } + } + + /** + * 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 '' . wxr_cdata($category->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 '' . wxr_cdata($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 '' . wxr_cdata($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 '' . wxr_cdata($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 '' . wxr_cdata($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 '' . wxr_cdata($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"; + echo '' . $author->ID . ''; + echo '' . $author->user_login . ''; + echo '' . $author->user_email . ''; + echo '' . wxr_cdata($author->display_name) . ''; + echo '' . wxr_cdata($author->user_firstname) . ''; + echo '' . wxr_cdata($author->user_lastname) . ''; + echo "\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); + + function sermon_return_attachment_id_from_url( $attachment_url ) { + global $wpdb; + $attachment_id = ''; + + //is attachment url set? + if ( $attachment_url !== '' ) { + //prepare query + + $query = $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE guid=%s", $attachment_url ); + + //get attachment id + $attachment_id = $wpdb->get_var( $query ); + } + + //return id + return $attachment_id; + } + + echo '\n"; + + ?> + + + + + + + + + + + + + + + + + + + + + + <?php bloginfo_rss('name'); ?> + + + + + + + + + + + + + term_id ?> + taxonomy; ?> + slug; ?> + parent ? $terms[$t->parent]->slug : ''; ?> + + + get_results($wpdb->prepare("SELECT * FROM $wpdb->termmeta WHERE term_id = %d", $t->term_id)); + foreach ($termmeta as $meta) : + /** + * Filter whether to selectively skip post meta used for WXR exports. + * + * Returning a truthy value to the filter will skip the current meta + * object from being exported. + * + * @since 3.3.0 + * + * @param bool $skip Whether to skip the current post meta. Default false. + * @param string $meta_key Current meta key. + * @param object $meta Current meta object. + */ + if (apply_filters('wxr_export_skip_postmeta', false, $meta->meta_key, $meta)) + continue; + ?> + + meta_key; ?> + meta_value); ?> + + + term_id, $assigned_term_images) ) { ?> + + sm_term_image_id + term_id]; ?> + + + + + + + + in_the_loop = true; // Fake being in the loop. + + /* NEW CODE START */ + $meta_value_array = array(); + $meta_key_name = array( + 'sermon_audio', + 'sermon_video', + 'sermon_video_link', + 'sermon_notes', + 'sermon_bulletin' + ); + foreach ($post_ids as $post) { + $postmeta = $wpdb->get_results($wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post)); + $postobject = $wpdb->get_results($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $post)); + $meta_value = array(); + if ($postobject[0]->post_type == $post_type_export) { + foreach ($postmeta as $meta) { + if ($meta->meta_key == '_thumbnail_id') { + $meta_value[] = $meta->meta_value; + } + if (in_array($meta->meta_key, $meta_key_name)) { + $attachment_id_temp = sermon_return_attachment_id_from_url($meta->meta_value); + if( !empty($attachment_id_temp) ) { + $meta_value[] = $attachment_id_temp; + } + } + } + } + if (isset($meta_value) && is_array($meta_value)) { + $meta_value_array = array_unique(array_merge($meta_value_array, $meta_value), SORT_REGULAR); + } + } + $attachment_array = array(); + foreach ($assigned_term_images as $term => $attachment) { + $attachment_array[] = $attachment; + } + $attachment_array = array_unique($attachment_array, SORT_REGULAR); + $post_ids = array_merge($post_ids, $meta_value_array, $attachment_array); + /* NEW CODE END */ + + // 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; + ?> + + + <?php echo apply_filters('the_title_rss', $post->post_title); ?> + + + + + + post_content)); + ?> + post_excerpt)); + ?> + ID; ?> + post_date; ?> + post_date_gmt; ?> + comment_status; ?> + ping_status; ?> + post_name; ?> + post_status; ?> + post_parent; ?> + menu_order; ?> + post_type; ?> + post_password; ?> + + ID); ?> + post_type == 'attachment') : ?> + ID); ?> + + get_results($wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID)); + foreach ($postmeta as $meta) : + /** + * Filter whether to selectively skip post meta used for WXR exports. + * + * Returning a truthy value to the filter will skip the current meta + * object from being exported. + * + * @since 3.3.0 + * + * @param bool $skip Whether to skip the current post meta. Default false. + * @param string $meta_key Current meta key. + * @param object $meta Current meta object. + */ + if (apply_filters('wxr_export_skip_postmeta', false, $meta->meta_key, $meta)) + continue; + ?> + + meta_key; ?> + meta_value); ?> + + + get_results($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID)); + foreach ($comments as $c) : ?> + + comment_ID; ?> + comment_author); ?> + comment_author_email; ?> + comment_author_url); ?> + comment_author_IP; ?> + comment_date; ?> + comment_date_gmt; ?> + comment_content) ?> + comment_approved; ?> + comment_type; ?> + comment_parent; ?> + user_id; ?> + get_results($wpdb->prepare("SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $c->comment_ID)); + foreach ($c_meta as $meta) : ?> + + meta_key; ?> + meta_value); ?> + + + + + + + + + log( 'Term "' . $book->book_name . '" already exists. (ID: ' . $term_data['term_id'] . ')' ); } else { $term_data = wp_insert_term( $book->book_name, 'wpfc_bible_book' ); - $this->log( 'Term "' . $book->book_name . '" imported. (ID: ' . $term_data['term_id'] . ')' ); + if ( ! $term_data instanceof WP_Error ) { + $this->log( 'Term "' . $book->book_name . '" imported. (ID: ' . $term_data['term_id'] . ')' ); + } else { + $this->log( 'Term "' . $book->book_name . '" not imported. (' . $term_data->get_error_code() . ': ' . $term_data->get_error_message() . ')' ); + continue; + } } $this->_imported_books[ $book->id ] = array( @@ -195,7 +200,12 @@ private function _import_preachers() { $term_data = wp_insert_term( $preacher->name, 'wpfc_preacher', array( 'desc' => apply_filters( 'sm_import_sb_preacher_description', $preacher->description ?: '' ) ) ); - $this->log( 'Term "' . $preacher->name . '" imported. (ID: ' . $term_data['term_id'] . ')' ); + if ( ! $term_data instanceof WP_Error ) { + $this->log( 'Term "' . $preacher->name . '" imported. (ID: ' . $term_data['term_id'] . ')' ); + } else { + $this->log( 'Term "' . $preacher->name . '" not imported. (' . $term_data->get_error_code() . ': ' . $term_data->get_error_message() . ')' ); + continue; + } } if ( $preacher->image !== '' ) { @@ -237,7 +247,12 @@ private function _import_series() { $this->log( 'Term "' . $item->name . '" already exists. (ID: ' . $term_data['term_id'] . ')' ); } else { $term_data = wp_insert_term( $item->name, 'wpfc_sermon_series' ); - $this->log( 'Term "' . $item->name . '" imported. (ID: ' . $term_data['term_id'] . ')' ); + if ( ! $term_data instanceof WP_Error ) { + $this->log( 'Term "' . $item->name . '" imported. (ID: ' . $term_data['term_id'] . ')' ); + } else { + $this->log( 'Term "' . $item->name . '" not imported. (' . $term_data->get_error_code() . ': ' . $term_data->get_error_message() . ')' ); + continue; + } } $this->_imported_series[ $item->id ] = array( @@ -264,7 +279,12 @@ private function _import_service_types() { $this->log( 'Term "' . $service->name . '" already exists. (ID: ' . $term_data['term_id'] . ')' ); } else { $term_data = wp_insert_term( $service->name, 'wpfc_sermon_series' ); - $this->log( 'Term "' . $service->name . '" imported. (ID: ' . $term_data['term_id'] . ')' ); + if ( ! $term_data instanceof WP_Error ) { + $this->log( 'Term "' . $service->name . '" imported. (ID: ' . $term_data['term_id'] . ')' ); + } else { + $this->log( 'Term "' . $service->name . '" not imported. (' . $term_data->get_error_code() . ': ' . $term_data->get_error_message() . ')' ); + continue; + } } $this->_imported_service_types[ $service->id ] = array( diff --git a/includes/admin/import/class-sm-import-se.php b/includes/admin/import/class-sm-import-se.php index 0be2b2d..cd795bf 100644 --- a/includes/admin/import/class-sm-import-se.php +++ b/includes/admin/import/class-sm-import-se.php @@ -62,9 +62,11 @@ private function _import_books() { $term_data = wp_insert_term( $book->book_name, 'wpfc_bible_book' ); } - $this->_imported_books[ $book->book_id ] = array( - 'new_id' => $term_data['term_id'], - ); + if ( ! $term_data instanceof WP_Error ) { + $this->_imported_books[ $book->book_id ] = array( + 'new_id' => $term_data['term_id'], + ); + } } } @@ -123,9 +125,11 @@ private function _import_speakers() { $term_data = wp_insert_term( trim( $speaker->first_name . ' ' . $speaker->last_name ), 'wpfc_preacher' ); } - $this->_imported_speakers[ $speaker->speaker_id ] = array( - 'new_id' => $term_data['term_id'], - ); + if ( ! $term_data instanceof WP_Error ) { + $this->_imported_speakers[ $speaker->speaker_id ] = array( + 'new_id' => $term_data['term_id'], + ); + } } } @@ -149,17 +153,19 @@ private function _import_series() { ) ); } - // Set image - $attachment_id = sm_import_and_set_post_thumbnail( $item->thumbnail_url, 0 ); - if ( is_int( $attachment_id ) ) { - $assigned_images = get_option( 'sermon_image_plugin' ); - $assigned_images[ $term_data['term_id'] ] = $attachment_id; - update_option( 'sermon_image_plugin', $assigned_images ); - } + if ( ! $term_data instanceof WP_Error ) { + // Set image + $attachment_id = sm_import_and_set_post_thumbnail( $item->thumbnail_url, 0 ); + if ( is_int( $attachment_id ) ) { + $assigned_images = get_option( 'sermon_image_plugin' ); + $assigned_images[ $term_data['term_id'] ] = $attachment_id; + update_option( 'sermon_image_plugin', $assigned_images ); + } - $this->_imported_series[ $item->series_id ] = array( - 'new_id' => $term_data['term_id'], - ); + $this->_imported_series[ $item->series_id ] = array( + 'new_id' => $term_data['term_id'], + ); + } } } @@ -181,9 +187,11 @@ private function _import_topics() { $term_data = wp_insert_term( $topic->name, 'wpfc_sermon_topics' ); } - $this->_imported_topics[ $topic->topic_id ] = array( - 'new_id' => $term_data['term_id'], - ); + if ( ! $term_data instanceof WP_Error ) { + $this->_imported_topics[ $topic->topic_id ] = array( + 'new_id' => $term_data['term_id'], + ); + } } } @@ -264,7 +272,7 @@ private function _import_messages() { ) ) ); } - if ( $id === 0 ) { + if ( $id === 0 || $id instanceof WP_Error) { // silently skip if error continue; } diff --git a/includes/admin/import/class-sm-import-sm.php b/includes/admin/import/class-sm-import-sm.php new file mode 100644 index 0000000..1347d94 --- /dev/null +++ b/includes/admin/import/class-sm-import-sm.php @@ -0,0 +1,1040 @@ +is_debug = ! ! \SermonManager::getOption( 'debug_import' ); + $this->start_time = microtime( true ); + } + + public function __destruct() { + update_option( 'sm_last_import_info', $this->debug_data ); + } + + /** + * Logs a message to show in debug + * + * @param string $message + * @param int $severity + * @param bool $no_time To hide time or not + * + * @since 2.11.0 + */ + public function log( $message = '', $severity = 254, $no_time = false ) { + $diff = microtime( true ) - $this->start_time; + $sec = sprintf( '%0' . ( 4 - strlen( intval( $diff ) ) ) . 'd', intval( $diff ) ); + $time = $sec . str_replace( '0.', '.', sprintf( '%.3f', $diff - intval( $diff ) ) ); + $line = ''; + + if ( ! $no_time ) { + $line .= "[${time}]"; + } + + switch ( $severity ) { + case 0: + $line .= ' (II)'; + break; + case 1: + $line .= ' (EE)'; + break; + case 2: + $line .= ' (WW)'; + break; + case 253: + $line .= ' '; + break; + case 254: + $line .= ' '; + break; + case 255: + $line .= ''; + } + + $this->debug_data .= $line . ' ' . $message . PHP_EOL; + } + + /** + * Do the import + */ + public function import() { + $this->log( 'Init info:' . PHP_EOL . 'Sermon Manager ' . SM_VERSION . PHP_EOL . 'Release Date: ' . date( 'Y-m-d', filemtime( SM_PLUGIN_FILE ) ), 255 ); + if ( ! doing_action( 'admin_init' ) ) { + $this->log( 'Scheduling for `admin_init` action.', 0 ); + add_action( 'admin_init', array( $this, __FUNCTION__ ) ); + + return; + } + + $this->log( 'Including import files.', 0 ); + require_once( ABSPATH . 'wp-admin/includes/import.php' ); + + if ( ! class_exists( 'WP_Importer' ) ) { + $class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php'; + if ( file_exists( $class_wp_importer ) ) + require $class_wp_importer; + } + $this->log( 'Files included.', 0 ); + + add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) ); + add_filter( 'http_request_timeout', array( $this, 'bump_request_timeout' ) ); + + $this->log( 'Doing `sm_import_before_sm` action.', 0 ); + do_action( 'sm_import_before_sm' ); + $this->log( 'Done.', 0 ); + + $this->log( 'Handling uploaded file.', 0 ); + $upload = $this->handle_upload(); + if($upload['status']) { + $this->log( 'File successfully loaded.', 0 ); + $this->log( 'Starting content import.', 0 ); + $this->importContent( $upload['file'] ); + $this->log( 'Content import ended.', 0 ); + } else { + /* Notify about failed file upload */ + $this->log( 'Error while loading export file', 0 ); + } + + $this->log( 'Doing `sm_import_after_sm` action.', 0 ); + do_action( 'sm_import_after_sm' ); + $this->log( 'Done.', 0 ); + } + + /** + * Handles the WXR upload and initial parsing of the file to prepare for + * displaying author import options + * + * @return bool False if error uploading or invalid file, true otherwise + */ + function handle_upload() { + $file = wp_import_handle_upload(); + $response = array(); + if ( isset( $file['error'] ) ) { + $response['status'] = false; + $this->log( 'Error message: ' . $file['error'] , 0 ); + } else if ( ! file_exists( $file['file'] ) ) { + $response['status'] = false; + $this->log( 'The export file could not be found. It is likely that this was caused by a permissions problem.' . $file['error'] , 0 ); + } + + $this->id = (int) $file['id']; + $this->log( 'Starting XML File parsing.', 0 ); + $import_data = $this->XMLparse( $file['file'] ); + if ( is_wp_error( $import_data ) ) { + $response['status'] = false; + $this->log( 'Parsing error: ' . $import_data->get_error_message(), 0 ); + } + + $this->version = $import_data['version']; + if ( $this->version > $this->max_wxr_version ) { + $response['status'] = false; + $this->log( 'This WXR file version may not be supported by this version of the importer. Please consider updating.', 0 ); + } + + $response['status'] = true; + $response['file'] = $file['file']; + $this->log( 'XML parsed with success.', 0 ); + return $response; + } + + /** + * The main controller for the actual import stage. + * + * @param string $file Path to the WXR file for importing + */ + function importContent( $file ) { + + $this->log( 'Import Content function started.', 0 ); + $this->import_start( $file ); + + $this->get_author_mapping(); + + wp_suspend_cache_invalidation( true ); + + $this->log( 'Process terms start.', 0 ); + $this->process_terms(); + $this->log( 'Process terms end.', 0 ); + + $this->log( 'Process posts start.', 0 ); + $this->process_posts(); + $this->log( 'Process posts end.', 0 ); + + wp_suspend_cache_invalidation( false ); + + // update incorrect/missing information in the DB + $this->log( 'Update incorrect/missing information in the DB.', 0 ); + + $this->log( 'Update parent/child relations start.', 0 ); + $this->backfill_parents(); + $this->log( 'Update parent/child relations end.', 0 ); + + $this->log( 'Update attachment urls start.', 0 ); + $this->backfill_attachment_urls(); + $this->log( 'Update attachment urls end.', 0 ); + + $this->log( 'Update featured image ids in posts start.', 0 ); + $this->remap_featured_images(); + $this->log( 'Update featured image ids in posts end.', 0 ); + + $this->log( 'Update term image ids in terms start.', 0 ); + $this->remap_term_images(); + $this->log( 'Update term image ids in terms end.', 0 ); + + $this->import_end(); + $this->log( 'Import Content function ended.', 0 ); + } + + /** + * Parses the WXR file and prepares us for the task of processing parsed data + * + * @param string $file Path to the WXR file for importing + */ + function import_start( $file ) { + if ( ! is_file($file) ) { + $this->import_status = false; + $this->log( 'The file does not exist, please try again.', 0 ); + return; + } + + $import_data = $this->XMLparse( $file ); + + if ( is_wp_error( $import_data ) ) { + $this->import_status = false; + $this->log( 'Import start error: ' .$import_data->get_error_message(), 0 ); + return; + } + + $this->log( 'Setup version.', 0 ); + $this->version = $import_data['version']; + $this->log( 'Setup authors.', 0 ); + $this->get_authors_from_import( $import_data ); + $this->log( 'Setup posts.', 0 ); + $this->posts = $import_data['posts']; + $this->log( 'Setup terms.', 0 ); + $this->terms = $import_data['terms']; + $this->log( 'Setup base url.', 0 ); + $this->base_url = esc_url( $import_data['base_url'] ); + + wp_defer_term_counting( true ); + wp_defer_comment_counting( true ); + + do_action( 'import_start' ); + } + + /** + * Retrieve authors from parsed WXR data + * + * Uses the provided author information from WXR 1.1 files + * or extracts info from each post for WXR 1.0 files + * + * @param array $import_data Data returned by a WXR parser + */ + function get_authors_from_import( $import_data ) { + $this->log( 'Importing authors start.', 0 ); + if ( ! empty( $import_data['authors'] ) ) { + $this->log( 'Authors exists, setting them.', 0 ); + $this->authors = $import_data['authors']; + // no author information, grab it from the posts + } else { + $this->log( 'Authors does not exist, getting them from posts.', 0 ); + foreach ( $import_data['posts'] as $post ) { + $login = sanitize_user( $post['post_author'], true ); + if ( empty( $login ) ) { + continue; + } + + + if ( ! isset($this->authors[$login]) ) + $this->authors[$login] = array( + 'author_login' => $login, + 'author_display_name' => $post['post_author'] + ); + } + } + } + + + /** + * Map old author logins to local user IDs. Can map to an existing user, create a new user + * or falls back to the current user in case of error with either of the previous + */ + function get_author_mapping() { + + $create_users = $this->allow_create_users(); + + if ( $create_users && $this->version != '1.0' ) { + $this->log( 'Users creation enabled.', 0 ); + foreach ( $this->authors as $i => $data ) { + + $santized_old_login = sanitize_user( $i, true ); + $old_id = isset( $this->authors[$i]['author_id'] ) ? intval($this->authors[$i]['author_id']) : false; + $this->log( 'Creating user.', 0 ); + $user_data = array( + 'user_login' => $i, + 'user_pass' => wp_generate_password(), + 'user_email' => isset( $this->authors[$i]['author_email'] ) ? $this->authors[$i]['author_email'] : '', + 'display_name' => $this->authors[$i]['author_display_name'], + 'first_name' => isset( $this->authors[$i]['author_first_name'] ) ? $this->authors[$i]['author_first_name'] : '', + 'last_name' => isset( $this->authors[$i]['author_last_name'] ) ? $this->authors[$i]['author_last_name'] : '', + ); + $user_id = wp_insert_user( $user_data ); + + if ( ! is_wp_error( $user_id ) ) { + if ( $old_id ) { + $this->processed_authors[$old_id] = $user_id; + } + $this->author_mapping[$santized_old_login] = $user_id; + } + + // failsafe: if the user_id was invalid, default to the current user + if ( ! isset( $this->author_mapping[$santized_old_login] ) ) { + $this->log( 'Some post does not have user assigned, use current user.', 0 ); + if ( $old_id ) { + $this->processed_authors[$old_id] = (int) get_current_user_id(); + } + $this->author_mapping[$santized_old_login] = (int) get_current_user_id(); + } + } + } + } + + /** + * Create new terms based on import information + * + * Doesn't create a term its slug already exists + */ + function process_terms() { + $this->log( 'Start terms processing.', 0 ); + if ( empty( $this->terms ) ) + return; + + foreach ( $this->terms as $term ) { + $this->log( 'Checking terms.', 0 ); + // if the term already exists in the correct taxonomy leave it alone + $term_id = term_exists( $term['slug'], $term['term_taxonomy'] ); + if ( $term_id ) { + if ( is_array($term_id) ) $term_id = $term_id['term_id']; + if ( isset($term['term_id']) ) + $this->processed_terms[intval($term['term_id'])] = (int) $term_id; + continue; + } + + if ( empty( $term['term_parent'] ) ) { + $parent = 0; + } else { + $parent = term_exists( $term['term_parent'], $term['term_taxonomy'] ); + if ( is_array( $parent ) ) $parent = $parent['term_id']; + } + $term = wp_slash( $term ); + $description = isset( $term['term_description'] ) ? $term['term_description'] : ''; + $termarr = array( 'slug' => $term['slug'], 'description' => $description, 'parent' => intval($parent) ); + + $this->log( 'Inserting terms.', 0 ); + $id = wp_insert_term( $term['term_name'], $term['term_taxonomy'], $termarr ); + if ( ! is_wp_error( $id ) ) { + if ( isset($term['term_id']) ) + $this->processed_terms[intval($term['term_id'])] = $id['term_id']; + } else { + $this->log( 'Inserting error: ' . $id->get_error_message(), 0 ); + continue; + } + + $this->log( 'Processing term meta start.', 0 ); + $this->process_termmeta( $term, $id['term_id'] ); + $this->log( 'Processing term meta end.', 0 ); + } + + unset( $this->terms ); + } + + /** + * Add metadata to imported term. + * + * @since 0.6.2 + * + * @param array $term Term data from WXR import. + * @param int $term_id ID of the newly created term. + */ + protected function process_termmeta( $term, $term_id ) { + if ( ! isset( $term['termmeta'] ) ) { + $term['termmeta'] = array(); + } + + if ( empty( $term['termmeta'] ) ) { + return; + } + + $this->log( 'Going over term meta.', 0 ); + foreach ( $term['termmeta'] as $meta ) { + $key = $meta['key']; + if ( ! $key ) { + continue; + } + + // Export gets meta straight from the DB so could have a serialized string + $value = maybe_unserialize( $meta['value'] ); + add_term_meta( $term_id, $key, $value ); + + if ($key == 'sm_term_image_id') { + $this->log( 'Term has image id set.', 0 ); + $assigned_term_images = get_option( 'sermon_image_plugin' ); + if( empty($assigned_term_images) ) { + $assigned_term_images = array(); + } + $assigned_term_images[$term_id] = $value; + update_option( 'sermon_image_plugin', $assigned_term_images ); + + $this->taxonomy_featured_images[$term_id] = (int) $value; + } + } + } + + /** + * Create new posts based on import information + * + * Posts marked as having a parent which doesn't exist will become top level items. + * Doesn't create a new post if: the post type doesn't exist, the given post ID + * is already noted as imported or a post with the same title and date already exists. + * Note that new/updated terms, comments and meta are imported for the last of the above. + */ + function process_posts() { + + foreach ( $this->posts as $post ) { + $this->log( 'Iterating over posts (sermon and attachment).', 0 ); + if ( ! post_type_exists( $post['post_type'] ) && ( $post['post_type'] != 'wpfc_sermon' || $post['post_type'] != 'attachment' ) ) { + continue; + } + + if ( isset( $this->processed_posts[$post['post_id']] ) && ! empty( $post['post_id'] ) ) { + continue; + } + + if ( $post['status'] == 'auto-draft' ) { + continue; + } + + $post_type_object = get_post_type_object( $post['post_type'] ); + + $post_exists = post_exists( $post['post_title'], '', $post['post_date'] ); + + if ( $post_exists && get_post_type( $post_exists ) == $post['post_type'] ) { + $comment_post_ID = $post_id = $post_exists; + $this->processed_posts[ intval( $post['post_id'] ) ] = intval( $post_exists ); + } else { + $post_parent = (int) $post['post_parent']; + if ( $post_parent ) { + // if we already know the parent, map it to the new local ID + if ( isset( $this->processed_posts[$post_parent] ) ) { + $post_parent = $this->processed_posts[$post_parent]; + // otherwise record the parent for later + } else { + $this->post_orphans[intval($post['post_id'])] = $post_parent; + $post_parent = 0; + } + } + + // map the post author + $author = sanitize_user( $post['post_author'], true ); + if ( isset( $this->author_mapping[$author] ) ) + $author = $this->author_mapping[$author]; + else + $author = (int) get_current_user_id(); + + $postdata = array( + 'import_id' => $post['post_id'], 'post_author' => $author, 'post_date' => $post['post_date'], + 'post_date_gmt' => $post['post_date_gmt'], 'post_content' => $post['post_content'], + 'post_excerpt' => $post['post_excerpt'], 'post_title' => $post['post_title'], + 'post_status' => $post['status'], 'post_name' => $post['post_name'], + 'comment_status' => $post['comment_status'], 'ping_status' => $post['ping_status'], + 'guid' => $post['guid'], 'post_parent' => $post_parent, 'menu_order' => $post['menu_order'], + 'post_type' => $post['post_type'], 'post_password' => $post['post_password'] + ); + + $original_post_ID = $post['post_id']; + + $postdata = wp_slash( $postdata ); + + if ( 'attachment' == $postdata['post_type'] ) { + $remote_url = ! empty($post['attachment_url']) ? $post['attachment_url'] : $post['guid']; + + // try to use _wp_attached file for upload folder placement to ensure the same location as the export site + // e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload() + $postdata['upload_date'] = $post['post_date']; + if ( isset( $post['postmeta'] ) ) { + foreach( $post['postmeta'] as $meta ) { + if ( $meta['key'] == '_wp_attached_file' ) { + if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta['value'], $matches ) ) + $postdata['upload_date'] = $matches[0]; + break; + } + } + } + + $comment_post_ID = $post_id = $this->process_attachment( $postdata, $remote_url ); + } else { + $comment_post_ID = $post_id = wp_insert_post( $postdata, true ); + } + + if ( is_wp_error( $post_id ) ) { + continue; + } + + if ( $post['is_sticky'] == 1 ) + stick_post( $post_id ); + } + + // map pre-import ID to local ID + $this->processed_posts[intval($post['post_id'])] = (int) $post_id; + + if ( ! isset( $post['terms'] ) ) + $post['terms'] = array(); + + // add categories, tags and other terms + if ( ! empty( $post['terms'] ) ) { + $terms_to_set = array(); + foreach ( $post['terms'] as $term ) { + // back compat with WXR 1.0 map 'tag' to 'post_tag' + $taxonomy = ( 'tag' == $term['domain'] ) ? 'post_tag' : $term['domain']; + $term_exists = term_exists( $term['slug'], $taxonomy ); + $term_id = is_array( $term_exists ) ? $term_exists['term_id'] : $term_exists; + if ( ! $term_id ) { + $t = wp_insert_term( $term['name'], $taxonomy, array( 'slug' => $term['slug'] ) ); + if ( ! is_wp_error( $t ) ) { + $term_id = $t['term_id']; + } else { + continue; + } + } + $terms_to_set[$taxonomy][] = intval( $term_id ); + } + + foreach ( $terms_to_set as $tax => $ids ) { + $tt_ids = wp_set_post_terms( $post_id, $ids, $tax ); + } + unset( $post['terms'], $terms_to_set ); + } + + if ( ! isset( $post['comments'] ) ) + $post['comments'] = array(); + + // add/update comments + if ( ! empty( $post['comments'] ) ) { + $num_comments = 0; + $inserted_comments = array(); + foreach ( $post['comments'] as $comment ) { + $comment_id = $comment['comment_id']; + $newcomments[$comment_id]['comment_post_ID'] = $comment_post_ID; + $newcomments[$comment_id]['comment_author'] = $comment['comment_author']; + $newcomments[$comment_id]['comment_author_email'] = $comment['comment_author_email']; + $newcomments[$comment_id]['comment_author_IP'] = $comment['comment_author_IP']; + $newcomments[$comment_id]['comment_author_url'] = $comment['comment_author_url']; + $newcomments[$comment_id]['comment_date'] = $comment['comment_date']; + $newcomments[$comment_id]['comment_date_gmt'] = $comment['comment_date_gmt']; + $newcomments[$comment_id]['comment_content'] = $comment['comment_content']; + $newcomments[$comment_id]['comment_approved'] = $comment['comment_approved']; + $newcomments[$comment_id]['comment_type'] = $comment['comment_type']; + $newcomments[$comment_id]['comment_parent'] = $comment['comment_parent']; + $newcomments[$comment_id]['commentmeta'] = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array(); + if ( isset( $this->processed_authors[$comment['comment_user_id']] ) ) + $newcomments[$comment_id]['user_id'] = $this->processed_authors[$comment['comment_user_id']]; + } + ksort( $newcomments ); + + foreach ( $newcomments as $key => $comment ) { + // if this is a new post we can skip the comment_exists() check + if ( ! $post_exists || ! comment_exists( $comment['comment_author'], $comment['comment_date'] ) ) { + if ( isset( $inserted_comments[$comment['comment_parent']] ) ) + $comment['comment_parent'] = $inserted_comments[$comment['comment_parent']]; + $comment = wp_filter_comment( $comment ); + $inserted_comments[$key] = wp_insert_comment( $comment ); + + foreach( $comment['commentmeta'] as $meta ) { + $value = maybe_unserialize( $meta['value'] ); + add_comment_meta( $inserted_comments[$key], $meta['key'], $value ); + } + + $num_comments++; + } + } + unset( $newcomments, $inserted_comments, $post['comments'] ); + } + + if ( ! isset( $post['postmeta'] ) ) + $post['postmeta'] = array(); + + // add/update post meta + if ( ! empty( $post['postmeta'] ) ) { + foreach ( $post['postmeta'] as $meta ) { + $key = $meta['key']; + $value = false; + + if ( '_edit_last' == $key ) { + if ( isset( $this->processed_authors[intval($meta['value'])] ) ) + $value = $this->processed_authors[intval($meta['value'])]; + else + $key = false; + } + + if ( $key ) { + // export gets meta straight from the DB so could have a serialized string + if ( ! $value ) + $value = maybe_unserialize( $meta['value'] ); + + add_post_meta( $post_id, $key, $value ); + + // if the post has a featured image, take note of this in case of remap + if ( '_thumbnail_id' == $key ) + $this->featured_images[$post_id] = (int) $value; + } + } + } + } + + unset( $this->posts ); + } + + /** + * If fetching attachments is enabled then attempt to create a new attachment + * + * @param array $post Attachment post details from WXR + * @param string $url URL to fetch attachment from + * @return int|WP_Error Post ID on success, WP_Error otherwise + */ + function process_attachment( $post, $url ) { + if ( ! $this->fetch_attachments ) + return new WP_Error( 'attachment_processing_error', + __( 'Fetching attachments is not enabled', 'wordpress-importer' ) ); + + // if the URL is absolute, but does not contain address, then upload it assuming base_site_url + if ( preg_match( '|^/[\w\W]+$|', $url ) ) + $url = rtrim( $this->base_url, '/' ) . $url; + + $upload = $this->fetch_remote_file( $url, $post ); + if ( is_wp_error( $upload ) ) + return $upload; + + if ( $info = wp_check_filetype( $upload['file'] ) ) + $post['post_mime_type'] = $info['type']; + else + return new WP_Error( 'attachment_processing_error', __('Invalid file type', 'wordpress-importer') ); + + $post['guid'] = $upload['url']; + + // as per wp-admin/includes/upload.php + $post_id = wp_insert_attachment( $post, $upload['file'] ); + wp_update_attachment_metadata( $post_id, wp_generate_attachment_metadata( $post_id, $upload['file'] ) ); + + // remap resized image URLs, works by stripping the extension and remapping the URL stub. + if ( preg_match( '!^image/!', $info['type'] ) ) { + $parts = pathinfo( $url ); + $name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2 + + $parts_new = pathinfo( $upload['url'] ); + $name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" ); + + $this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new; + } + + return $post_id; + } + + /** + * Attempt to download a remote file attachment + * + * @param string $url URL of item to fetch + * @param array $post Attachment details + * @return array|WP_Error Local file location details on success, WP_Error otherwise + */ + function fetch_remote_file( $url, $post ) { + // extract the file name and extension from the url + $file_name = basename( $url ); + + // get placeholder file in the upload dir with a unique, sanitized filename + $upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] ); + if ( $upload['error'] ) + return new WP_Error( 'upload_dir_error', $upload['error'] ); + + // fetch the remote url and write it to the placeholder file + $headers = wp_get_http( $url, $upload['file'] ); + + // request failed + if ( ! $headers ) { + @unlink( $upload['file'] ); + return new WP_Error( 'import_file_error', __('Remote server did not respond', 'wordpress-importer') ); + } + + // make sure the fetch was successful + if ( $headers['response'] != '200' ) { + @unlink( $upload['file'] ); + return new WP_Error( 'import_file_error', sprintf( __('Remote server returned error response %1$d %2$s', 'wordpress-importer'), esc_html($headers['response']), get_status_header_desc($headers['response']) ) ); + } + + $filesize = filesize( $upload['file'] ); + + if ( isset( $headers['content-length'] ) && $filesize != $headers['content-length'] ) { + @unlink( $upload['file'] ); + return new WP_Error( 'import_file_error', __('Remote file is incorrect size', 'wordpress-importer') ); + } + + if ( 0 == $filesize ) { + @unlink( $upload['file'] ); + return new WP_Error( 'import_file_error', __('Zero size file downloaded', 'wordpress-importer') ); + } + + $max_size = (int) $this->max_attachment_size(); + if ( ! empty( $max_size ) && $filesize > $max_size ) { + @unlink( $upload['file'] ); + return new WP_Error( 'import_file_error', sprintf(__('Remote file is too large, limit is %s', 'wordpress-importer'), size_format($max_size) ) ); + } + + // keep track of the old and new urls so we can substitute them later + $this->url_remap[$url] = $upload['url']; + $this->url_remap[$post['guid']] = $upload['url']; // r13735, really needed? + // keep track of the destination if the remote url is redirected somewhere else + if ( isset($headers['x-final-location']) && $headers['x-final-location'] != $url ) + $this->url_remap[$headers['x-final-location']] = $upload['url']; + + return $upload; + } + + /** + * Attempt to associate posts with previously missing parents + * + * An imported post's parent may not have been imported when it was first created + * so try again. + */ + function backfill_parents() { + global $wpdb; + + // find parents for post orphans + foreach ( $this->post_orphans as $child_id => $parent_id ) { + $local_child_id = $local_parent_id = false; + if ( isset( $this->processed_posts[$child_id] ) ) + $local_child_id = $this->processed_posts[$child_id]; + if ( isset( $this->processed_posts[$parent_id] ) ) + $local_parent_id = $this->processed_posts[$parent_id]; + + if ( $local_child_id && $local_parent_id ) + $wpdb->update( $wpdb->posts, array( 'post_parent' => $local_parent_id ), array( 'ID' => $local_child_id ), '%d', '%d' ); + } + } + + /** + * Use stored mapping information to update old attachment URLs + */ + function backfill_attachment_urls() { + global $wpdb; + // make sure we do the longest urls first, in case one is a substring of another + uksort( $this->url_remap, array(&$this, 'cmpr_strlen') ); + + foreach ( $this->url_remap as $from_url => $to_url ) { + // remap urls in post_content + $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url) ); + // remap enclosure urls + $result = $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url) ); + } + } + + // return the difference in length between two strings + function cmpr_strlen( $a, $b ) { + return strlen($b) - strlen($a); + } + + /** + * Update _thumbnail_id meta to new, imported attachment IDs + */ + function remap_featured_images() { + // cycle through posts that have a featured image + foreach ( $this->featured_images as $post_id => $value ) { + if ( isset( $this->processed_posts[$value] ) ) { + $new_id = $this->processed_posts[$value]; + // only update if there's a difference + if ( $new_id != $value ) + update_post_meta( $post_id, '_thumbnail_id', $new_id ); + } + } + } + + /** + * Update sm_term_image_id meta to new, imported attachment IDs + */ + function remap_term_images() { + // cycle through posts that have a featured image + foreach ( $this->taxonomy_featured_images as $term_id => $value ) { + if ( isset( $this->processed_posts[$value] ) ) { + $new_id = $this->processed_posts[$value]; + // only update if there's a difference + if ( $new_id != $value ) { + $assigned_term_images = get_option( 'sermon_image_plugin' ); + $assigned_term_images[$term_id] = $new_id; + update_option( 'sermon_image_plugin', $assigned_term_images ); + } + } + } + } + + /** + * Performs post-import cleanup of files and the cache + */ + function import_end() { + wp_import_cleanup( $this->id ); + + wp_cache_flush(); + foreach ( get_taxonomies() as $tax ) { + delete_option( "{$tax}_children" ); + _get_term_hierarchy( $tax ); + } + + wp_defer_term_counting( false ); + wp_defer_comment_counting( false ); + + do_action( 'import_end' ); + } + + /* WXR Functions - Start */ + + function XMLparse( $file ) { + $this->wxr_version = $this->in_post = $this->cdata = $this->data = $this->sub_data = $this->in_tag = $this->in_sub_tag = false; + $this->authors = $this->posts = $this->term = $this->category = $this->tag = array(); + + $this->log( 'XML parser setup.', 0 ); + $xml = xml_parser_create( 'UTF-8' ); + 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' ); + + $this->log( 'Parsing content.', 0 ); + if ( ! xml_parse( $xml, file_get_contents( $file ), true ) ) { + $current_line = xml_get_current_line_number( $xml ); + $current_column = xml_get_current_column_number( $xml ); + $error_code = xml_get_error_code( $xml ); + $error_string = xml_error_string( $error_code ); + $this->log( 'There was an error when reading this WXR file.', 0 ); + return new WP_Error( 'XML_parse_error', 'There was an error when reading this WXR file', array( $current_line, $current_column, $error_string ) ); + } + xml_parser_free( $xml ); + + if ( ! preg_match( '/^\d+\.\d+$/', $this->wxr_version ) ) { + $this->log( 'This does not appear to be a WXR file, missing/invalid WXR version number.', 0 ); + return new WP_Error( 'WXR_parse_error', __( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'wordpress-importer' ) ); + } + + $this->log( 'Setting content parameters.', 0 ); + return array( + 'authors' => $this->authors, + 'posts' => $this->posts, + 'categories' => $this->category, + 'tags' => $this->tag, + 'terms' => $this->term, + 'base_url' => $this->base_url, + 'version' => $this->wxr_version + ); + } + + function tag_open( $parse, $tag, $attr ) { + $this->log( 'Opening tags.', 0 ); + if ( in_array( $tag, $this->wp_tags ) ) { + $this->in_tag = substr( $tag, 3 ); + return; + } + + if ( in_array( $tag, $this->wp_sub_tags ) ) { + $this->in_sub_tag = substr( $tag, 3 ); + return; + } + + switch ( $tag ) { + case 'category': + if ( isset($attr['domain'], $attr['nicename']) ) { + $this->sub_data['domain'] = $attr['domain']; + $this->sub_data['slug'] = $attr['nicename']; + } + break; + case 'item': $this->in_post = true; + case 'title': if ( $this->in_post ) $this->in_tag = 'post_title'; break; + case 'guid': $this->in_tag = 'guid'; break; + case 'dc:creator': $this->in_tag = 'post_author'; break; + case 'content:encoded': $this->in_tag = 'post_content'; break; + case 'excerpt:encoded': $this->in_tag = 'post_excerpt'; break; + + case 'wp:term_slug': $this->in_tag = 'slug'; break; + case 'wp:meta_key': $this->in_sub_tag = 'key'; break; + case 'wp:meta_value': $this->in_sub_tag = 'value'; break; + } + } + + function cdata( $parser, $cdata ) { + $this->log( 'Handling data.', 0 ); + if ( ! trim( $cdata ) ) + return; + + if ( false !== $this->in_tag || false !== $this->in_sub_tag ) { + $this->cdata .= $cdata; + } else { + $this->cdata .= trim( $cdata ); + } + } + + function tag_close( $parser, $tag ) { + $this->log( 'Closing tag.', 0 ); + switch ( $tag ) { + case 'wp:comment': + unset( $this->sub_data['key'], $this->sub_data['value'] ); // remove meta sub_data + if ( ! empty( $this->sub_data ) ) + $this->data['comments'][] = $this->sub_data; + $this->sub_data = false; + break; + case 'wp:commentmeta': + $this->sub_data['commentmeta'][] = array( + 'key' => $this->sub_data['key'], + 'value' => $this->sub_data['value'] + ); + break; + case 'category': + if ( ! empty( $this->sub_data ) ) { + $this->sub_data['name'] = $this->cdata; + $this->data['terms'][] = $this->sub_data; + } + $this->sub_data = false; + break; + case 'wp:postmeta': + if ( ! empty( $this->sub_data ) ) + $this->data['postmeta'][] = $this->sub_data; + $this->sub_data = false; + break; + case 'wp:termmeta': + if ( ! empty( $this->sub_data ) ) + $this->data['termmeta'][] = $this->sub_data; + $this->sub_data = false; + break; + case 'item': + $this->posts[] = $this->data; + $this->data = false; + break; + case 'wp:category': + case 'wp:tag': + case 'wp:term': + $n = substr( $tag, 3 ); + array_push( $this->$n, $this->data ); + $this->data = false; + break; + case 'wp:author': + if ( ! empty($this->data['author_login']) ) + $this->authors[$this->data['author_login']] = $this->data; + $this->data = false; + break; + case 'wp:base_site_url': + $this->base_url = $this->cdata; + break; + case 'wp:wxr_version': + $this->wxr_version = $this->cdata; + break; + + default: + if ( $this->in_sub_tag ) { + $this->sub_data[$this->in_sub_tag] = ! empty( $this->cdata ) ? $this->cdata : ''; + $this->in_sub_tag = false; + } else if ( $this->in_tag ) { + $this->data[$this->in_tag] = ! empty( $this->cdata ) ? $this->cdata : ''; + $this->in_tag = false; + } + } + + $this->cdata = false; + } + + /* WXR Functions - End */ +} \ No newline at end of file diff --git a/includes/admin/settings/class-sm-settings-debug.php b/includes/admin/settings/class-sm-settings-debug.php index 6602207..0dab626 100644 --- a/includes/admin/settings/class-sm-settings-debug.php +++ b/includes/admin/settings/class-sm-settings-debug.php @@ -25,6 +25,12 @@ public function get_settings() { 'desc' => '', 'id' => 'debug_settings' ), + array( + 'title' => __( 'Enable output of PHP errors in Sermon Manager (disable in production)', 'sermon-manager-for-wordpress' ), + 'type' => 'checkbox', + 'id' => 'sm_debug', + 'default' => 'no', + ), array( 'title' => __( 'Force Sermon Manager\'s WP_Background_Updater class', 'sermon-manager-for-wordpress' ), 'type' => 'checkbox', @@ -74,6 +80,13 @@ public function get_settings() { 'id' => 'post_excerpt_enabled', 'default' => 1, ), + array( + 'title' => 'Use home_url in dropdown filter', + 'type' => 'checkbox', + 'id' => 'home_url_filtering', + 'desc' => 'Check this if you have HTTP 404 error when you use filtering', + 'default' => 0, + ), array( 'title' => __( 'Execute a specific update function' ), 'type' => 'select', @@ -82,6 +95,20 @@ public function get_settings() { 'options' => sm_debug_get_update_functions(), 'desc' => '[AE] - Already Executed; [NE] - Not Executed', ), + array( + 'title' => 'Disable override of the_excerpt', + 'type' => 'checkbox', + 'id' => 'disable_the_excerpt', + 'desc' => 'Check this if you have double sermon content on archive page', + 'default' => 0, + ), + array( + 'title' => 'Load Plyr JS in footer (applies only to Plyr player)', + 'type' => 'checkbox', + 'id' => 'player_js_footer', + 'desc' => 'Check this if Plyr is not loading', + 'default' => 0, + ), array( 'type' => 'sectionend', 'id' => 'debug_settings' ), ) ); diff --git a/includes/admin/settings/class-sm-settings-general.php b/includes/admin/settings/class-sm-settings-general.php index 718a8ae..2b1b0b0 100644 --- a/includes/admin/settings/class-sm-settings-general.php +++ b/includes/admin/settings/class-sm-settings-general.php @@ -51,13 +51,11 @@ public function get_settings() { 'default' => 'no', ), array( - 'title' => __( 'Enable Template Files', 'sermon-manager-for-wordpress' ), + 'title' => __( 'Theme Compatibility', 'sermon-manager-for-wordpress' ), 'type' => 'checkbox', - // translators: %s effectively /views - // translators: Since /views is a locale independent folder name it MUST NOT be localized - 'desc' => wp_sprintf( __( 'Enable template files found in the %s folder', 'sermon-manager-for-wordpress' ), '/views' ), - 'desc_tip' => __( 'This is for users upgrading from an older version who have issues with version 1.5+.', 'sermon-manager-for-wordpress' ), - 'id' => 'template', + 'desc' => __( 'Enable this if your sermon layout looks broken.', 'sermon-manager-for-wordpress' ), + 'desc_tip' => __( 'This will disable full-page layout override, and use alternative layout algorithm.', 'sermon-manager-for-wordpress' ), + 'id' => 'theme_compatibility', 'default' => 'no', ), array( @@ -72,14 +70,12 @@ public function get_settings() { array( 'title' => __( 'Display audio player or video on archive pages', 'sermon-manager-for-wordpress' ), 'type' => 'checkbox', - 'desc' => __( 'Display audio player or video on archive pages', 'sermon-manager-for-wordpress' ), 'id' => 'archive_player', 'default' => 'no', ), array( 'title' => __( 'Display attachments on archive pages', 'sermon-manager-for-wordpress' ), 'type' => 'checkbox', - 'desc' => __( 'Display attachments on archive pages', 'sermon-manager-for-wordpress' ), 'id' => 'archive_meta', 'default' => 'no', ), diff --git a/includes/admin/views/html-admin-import-export.php b/includes/admin/views/html-admin-import-export.php index 427584e..97be4ab 100644 --- a/includes/admin/views/html-admin-import-export.php +++ b/includes/admin/views/html-admin-import-export.php @@ -6,7 +6,7 @@

-
+
<?php esc_attr_e( 'Import from file', 'sermon-manager-for-wordpress' ) ?> @@ -17,11 +17,41 @@
-
+
<?php esc_attr_e( 'Export to file', 'sermon-manager-for-wordpress' ) ?> @@ -44,12 +74,12 @@
'; + + return $html; +} + +/** + * Render sermon image, if not set try series image, if not set too - try preacher + * + * @param string $size Image size, supports WP image size + * + * @deprecated 2.12.0 + */ +function render_sermon_image( $size ) { + //$size = any defined image size in WordPress + if ( has_post_thumbnail() ) : + the_post_thumbnail( $size ); + elseif ( apply_filters( 'sermon-images-list-the-terms', '', array( 'taxonomy' => 'wpfc_sermon_series', ) ) ) : + // get series image + print apply_filters( 'sermon-images-list-the-terms', '', array( + 'image_size' => $size, + 'taxonomy' => 'wpfc_sermon_series', + 'after' => '', + 'after_image' => '', + 'before' => '', + 'before_image' => '' + ) ); + elseif ( ! has_post_thumbnail() && ! apply_filters( 'sermon-images-list-the-terms', '', array( 'taxonomy' => 'wpfc_sermon_series', ) ) ) : + // get speaker image + print apply_filters( 'sermon-images-list-the-terms', '', array( + 'image_size' => $size, + 'taxonomy' => 'wpfc_preacher', + 'after' => '', + 'after_image' => '', + 'before' => '', + 'before_image' => '' + ) ); + endif; +} + +/** + * Renders video and/or audio with wrapper HTML + * + * @return string The HTML + * + * @deprecated 2.12.0 + */ +function wpfc_sermon_media() { + $html = ''; + + if ( get_wpfc_sermon_meta( 'sermon_video_link' ) ) { + $html .= ''; + } else { + $html .= '
'; + $html .= do_shortcode( get_wpfc_sermon_meta( 'sermon_video' ) ); + $html .= '
'; + } + + if ( get_wpfc_sermon_meta( 'sermon_audio' ) ) { + $html .= '
'; + $html .= wpfc_render_audio( get_wpfc_sermon_meta( 'sermon_audio' ) ); + $html .= '
'; + } + + return $html; +} + +/** + * @deprecated 2.12.0 + */ +function wpfc_sermon_author_filter() { + _deprecated_function( __FUNCTION__, '2.12.0', null ); +} diff --git a/includes/sm-template-functions.php b/includes/sm-template-functions.php new file mode 100755 index 0000000..23260ba --- /dev/null +++ b/includes/sm-template-functions.php @@ -0,0 +1,671 @@ +taxonomy . '.php'; + + if ( ! file_exists( get_stylesheet_directory() . '/' . $default_file ) ) { + $default_file = 'archive-wpfc_sermon.php'; + } + } else { + $default_file = 'archive-wpfc_sermon.php'; + } + } elseif ( is_post_type_archive( 'wpfc_sermon' ) ) { + $default_file = 'archive-wpfc_sermon.php'; + } else { + $default_file = ''; + } + + if ( $default_file ) { + if ( file_exists( get_stylesheet_directory() . '/' . $default_file ) ) { + return get_stylesheet_directory() . '/' . $default_file; + } + + return SM_PATH . 'views/' . $default_file; + } + + return $template; + } ); +} + +/** + * Replaces default the_content and/or the_excerpt with proper sermon content + * + * @param string $content The default content + * + * @return string The modified content if it's Sermon related data + */ +function add_wpfc_sermon_content( $content ) { + if ( 'wpfc_sermon' === get_post_type() && in_the_loop() == true ) { + if ( ! is_feed() && ( is_archive() || is_search() ) ) { + $content = wpfc_sermon_excerpt_v2( true ); + } elseif ( is_singular() && is_main_query() ) { + $content = wpfc_sermon_single_v2( true ); + } + } + + return $content; +} + +add_filter( 'the_content', 'add_wpfc_sermon_content' ); +if ( ! \SermonManager::getOption( 'disable_the_excerpt' ) ) { + add_filter( 'the_excerpt', 'add_wpfc_sermon_content' ); +} + +/** + * Render sermon sorting/filtering + * + * @param array $args Display options. See the 'sermon_sort_fields' shortcode for array items + * + * @see WPFC_Shortcodes->displaySermonSorting() + * + * @return string the HTML + * + * @since 2.5.0 added $args + */ +function render_wpfc_sorting( $args = array() ) { + $action = ( SermonManager::getOption( 'home_url_filtering' ) ? home_url() : site_url() ) . '/' . ( SermonManager::getOption( 'common_base_slug' ) ? ( SermonManager::getOption( 'archive_slug' ) ?: 'sermons' ) : '' ); + + // Filters HTML fields data + $filters = array( + array( + 'className' => 'sortPreacher', + 'taxonomy' => 'wpfc_preacher', + /* Translators: %s: Preacher label (sentence case; singular) */ + 'title' => sprintf( __( 'Filter by %s', 'sermon-manager-for-wordpress' ), \SermonManager::getOption( 'preacher_label' ) ?: 'Preacher' ), + ), + array( + 'className' => 'sortSeries', + 'taxonomy' => 'wpfc_sermon_series', + 'title' => __( 'Filter by Series', 'sermon-manager-for-wordpress' ) + ), + array( + 'className' => 'sortTopics', + 'taxonomy' => 'wpfc_sermon_topics', + 'title' => __( 'Filter by Topic', 'sermon-manager-for-wordpress' ) + ), + array( + 'className' => 'sortBooks', + 'taxonomy' => 'wpfc_bible_book', + 'title' => __( 'Filter by Book', 'sermon-manager-for-wordpress' ) + ), + ); + + ob_start(); ?> +
+ + +
+
+ + + 1 ): ?> + + + + + + + + + 1 ): ?> + + + + + + + + +
+
+ + +
+ ID, $meta_key, true ); + if ( $data !== '' ) { + return $data; + } + + return null; +} + +/** + * Pass sermon content through WordPres functions, to render shortcodes, etc + * + * @param string $meta_key Sermon meta key + * @param int $post_id Post ID + * + * @return string The processed content + */ +function process_wysiwyg_output( $meta_key, $post_id = 0 ) { + global $wp_embed; + + $post_id = $post_id ? $post_id : get_the_id(); + + $content = get_post_meta( $post_id, $meta_key, true ); + $content = $wp_embed->autoembed( $content ); + $content = $wp_embed->run_shortcode( $content ); + $content = wpautop( $content ); + $content = do_shortcode( $content ); + + return $content; +} + +/** + * Render sermon description + * + * @param string $before content before description + * @param string $after content after description + * @param bool $return True to return, false to echo (default) + * + * @return string The HTML, if $return is set to true + */ +function wpfc_sermon_description( $before = '', $after = '', $return = false ) { + $output = $before . wpautop( process_wysiwyg_output( 'sermon_description', get_the_ID() ) ) . $after; + + if ( ! $return ) { + echo $output; + } + + return $output; +} + +/** + * Returns sermon image URL + * + * @param bool $fallback If set to true, it will try to get series image URL if sermon image URL is not set + * + * @return string Image URL or empty string + * + * @since 2.12.0 + */ +function get_sermon_image_url( $fallback = true ) { + if ( get_the_post_thumbnail_url() ) { + return get_the_post_thumbnail_url(); + } + + if ( $fallback ) { + foreach ( + apply_filters( 'sermon-images-get-the-terms', '', array( + 'post_id' => get_the_ID() + ) ) as $term + ) { + if ( isset( $term->image_id ) && $term->image_id !== 0 ) { + $image = wp_get_attachment_image_url( $term->image_id, 'full' ); + if ( $image ) { + return $image; + } + } + } + } + + return ''; +} + +/** + * Renders the video player + * + * @param string $url The URL of the video file + * + * @return string Video player HTML + * + * @since 2.11.0 + */ +function wpfc_render_video( $url = '' ) { + if ( ! is_string( $url ) || trim( $url ) === '' ) { + return ''; + } + + $player = \SermonManager::getOption( 'player' ) ?: 'plyr'; + + if ( $player === 'wordpress' ) { + $attr = array( + 'src' => $url, + 'preload' => 'none' + ); + + $output = wp_video_shortcode( $attr ); + } else { + $is_youtube_long = strpos( strtolower( $url ), 'youtube.com' ); + $is_youtube_short = strpos( strtolower( $url ), 'youtu.be' ); + $is_youtube = $is_youtube_long || $is_youtube_short; + $is_vimeo = strpos( strtolower( $url ), 'vimeo.com' ); + + if ( $is_youtube || $is_vimeo ) { + $output = '
'; + } else { + $output = ''; + } + } + + /** + * Allows changing of the video player to any HTML + * + * @param string $output Video player HTML + * @param string $url Video source URL + */ + return apply_filters( 'sm_video_player', $output, $url ); +} + +/** + * Renders the audio player + * + * @param string $url The URL of the audio file + * + * @return string Audio player HTML + */ +function wpfc_render_audio( $url = '' ) { + if ( ! is_string( $url ) || trim( $url ) === '' ) { + return ''; + } + + $player = \SermonManager::getOption( 'player' ) ?: 'plyr'; + + if ( $player === 'wordpress' ) { + $attr = array( + 'src' => $url, + 'preload' => 'none' + ); + + $output = wp_audio_shortcode( $attr ); + } else { + $output = ''; + } + + /** + * Allows changing of the audio player to any HTML + * + * @param string $output Audio player HTML + * @param string $url Audio source URL + */ + return apply_filters( 'sm_audio_player', $output, $url ); +} + +/** + * Render sermon attachments HTML + * + * @return string + */ +function wpfc_sermon_attachments() { + if ( ! get_wpfc_sermon_meta( 'sermon_audio' ) && + ! get_wpfc_sermon_meta( 'sermon_notes' ) && + ! get_wpfc_sermon_meta( 'sermon_bulletin' ) ) { + return ''; + } + + $html = '
'; + $html .= '

' . __( 'Download Files', 'sermon-manager-for-wordpress' ) . ''; + if ( get_wpfc_sermon_meta( 'sermon_audio' ) ) { + $html .= '' . __( 'MP3', 'sermon-manager-for-wordpress' ) . ''; + } + if ( get_wpfc_sermon_meta( 'sermon_notes' ) ) { + $html .= '' . __( 'Notes', 'sermon-manager-for-wordpress' ) . ''; + } + if ( get_wpfc_sermon_meta( 'sermon_bulletin' ) ) { + $html .= '' . __( 'Bulletin', 'sermon-manager-for-wordpress' ) . ''; + } + $html .= '

'; + $html .= '
'; + + return apply_filters( 'sm_attachments_html', $html ); +} + +/** + * Renders updates single sermon view + * + * @param bool $return True to return output, false to echo (default) + * @param WP_Post $post WP_Post instance of the sermon + * + * @return string The HTML if $return is set to true + */ +function wpfc_sermon_single_v2( $return = false, $post = null ) { + if ( $post === null ) { + global $post; + } + + ob_start(); + ?> + +
> +
+
+
+
+ +
+

+
+ ID ) ) : ?> +
+ + ID, 'wpfc_preacher' ) ?> +
+ + ID ) ) : ?> +
+ + ID, 'wpfc_sermon_series' ) ?> +
+ + ID, 'bible_passage', true ) ) : ?> +
+ + +
+ + ID ) ) : ?> +
+ + ID, 'wpfc_service_type' ) ?> +
+ +
+
+ +
+ + + + +
+ +
+ + + +
+ +
+ +
+ +
+ +
+ + ID ) ) : ?> +
+ + ID, 'wpfc_sermon_topics' ) ?> +
+ +
+
+
+ + + +
> + +
+ +
+ +
+
+
+ +
+ ID ) ) : ?> +
+ ID, 'wpfc_sermon_series' ) ?> +
+ + +

+ +

+ +
+ +
+
+ +
+
+ +
+ + + fields for > - - - - - 1 ): ?> - - - - - - - - - 1 ): ?> - - - - - - - - - -
- - -
- ID, $args, true ); - if ( $data != '' ) { - echo $before . $data . $after; - } - - echo ''; -} - -// return any sermon meta -function get_wpfc_sermon_meta( $args ) { - global $post; - $data = get_post_meta( $post->ID, $args, true ); - if ( $data != '' ) { - return $data; - } - - return null; -} - -function process_wysiwyg_output( $meta_key, $post_id = 0 ) { - global $wp_embed; - - $post_id = $post_id ? $post_id : get_the_id(); - - $content = get_post_meta( $post_id, $meta_key, true ); - $content = $wp_embed->autoembed( $content ); - $content = $wp_embed->run_shortcode( $content ); - $content = wpautop( $content ); - $content = do_shortcode( $content ); - - return $content; -} - -// render/return sermon description -function wpfc_sermon_description( $before = '', $after = '', $return = false ) { - global $post; - $output = $before . wpautop( process_wysiwyg_output( 'sermon_description', get_the_ID() ) ) . $after; - - if ( $return ) { - return $output; - } else { - echo $output; - } -} - -// Change the_author to the preacher on frontend display -function wpfc_sermon_author_filter() { - global $post; - $preacher = the_terms( $post->ID, 'wpfc_preacher', '', ', ', ' ' ); - - return $preacher; -} - -//add_filter('the_author', 'wpfc_sermon_author_filter'); - -// render sermon image - loops through featured image, series image, speaker image, none -function render_sermon_image( $size ) { - //$size = any defined image size in WordPress - if ( has_post_thumbnail() ) : - the_post_thumbnail( $size ); - elseif ( apply_filters( 'sermon-images-list-the-terms', '', array( 'taxonomy' => 'wpfc_sermon_series', ) ) ) : - // get series image - print apply_filters( 'sermon-images-list-the-terms', '', array( - 'image_size' => $size, - 'taxonomy' => 'wpfc_sermon_series', - 'after' => '', - 'after_image' => '', - 'before' => '', - 'before_image' => '' - ) ); - elseif ( ! has_post_thumbnail() && ! apply_filters( 'sermon-images-list-the-terms', '', array( 'taxonomy' => 'wpfc_sermon_series', ) ) ) : - // get speaker image - print apply_filters( 'sermon-images-list-the-terms', '', array( - 'image_size' => $size, - 'taxonomy' => 'wpfc_preacher', - 'after' => '', - 'after_image' => '', - 'before' => '', - 'before_image' => '' - ) ); - endif; -} - -/* - * render media files section - * for template files use - * do_action ('sermon_media'); - * - */ -function wpfc_sermon_media() { - $html = ''; - - if ( get_wpfc_sermon_meta( 'sermon_video_link' ) ) { - $html .= ''; - } else { - $html .= '
'; - $html .= do_shortcode( get_wpfc_sermon_meta( 'sermon_video' ) ); - $html .= '
'; - } - - if ( get_wpfc_sermon_meta( 'sermon_audio' ) ) { - $html .= '
'; - $html .= wpfc_render_audio( get_wpfc_sermon_meta( 'sermon_audio' ) ); - $html .= '
'; - } - - return $html; -} - -/** - * Renders the video player - * - * @param string $url The URL of the video file - * - * @return string Video player HTML - * - * @since 2.11.0 - */ -function wpfc_render_video( $url = '' ) { - if ( ! is_string( $url ) || trim( $url ) === '' ) { - return ''; - } - - $player = \SermonManager::getOption( 'player' ) ?: 'plyr'; - - if ( $player === 'wordpress' ) { - $attr = array( - 'src' => $url, - 'preload' => 'none' - ); - - $output = wp_video_shortcode( $attr ); - } else { - $is_youtube_long = strpos( strtolower( $url ), 'youtube.com' ); - $is_youtube_short = strpos( strtolower( $url ), 'youtu.be' ); - $is_youtube = $is_youtube_long || $is_youtube_short; - $is_vimeo = strpos( strtolower( $url ), 'vimeo.com' ); - - if ( $is_youtube || $is_vimeo ) { - $output = '
'; - } else { - $output = ''; - } - } - - /** - * Allows changing of the video player to any HTML - * - * @param string $output Video player HTML - * @param string $url Video source URL - */ - return apply_filters( 'sm_video_player', $output, $url ); -} - -/** - * Renders the audio player - * - * @param string $url The URL of the audio file - * - * @return string Audio player HTML - */ -function wpfc_render_audio( $url = '' ) { - if ( ! is_string( $url ) || trim( $url ) === '' ) { - return ''; - } - - $player = \SermonManager::getOption( 'player' ) ?: 'plyr'; - - if ( $player === 'wordpress' ) { - $attr = array( - 'src' => $url, - 'preload' => 'none' - ); - - $output = wp_audio_shortcode( $attr ); - } else { - $output = ''; - } - - /** - * Allows changing of the audio player to any HTML - * - * @param string $output Audio player HTML - * @param string $url Audio source URL - */ - return apply_filters( 'sm_audio_player', $output, $url ); -} - -// legacy function -function wpfc_sermon_files() { - do_action( 'sermon_media' ); -} - -// just get the sermon audio -function wpfc_sermon_audio() { - $html = ''; - $html .= '
'; - $html .= wpfc_render_audio( get_wpfc_sermon_meta( 'sermon_audio' ) ); - $html .= '
'; - - return $html; -} - -// render additional files -function wpfc_sermon_attachments() { - global $post; - - if ( ! get_wpfc_sermon_meta( 'sermon_audio' ) && - ! get_wpfc_sermon_meta( 'sermon_notes' ) && - ! get_wpfc_sermon_meta( 'sermon_bulletin' ) ) { - return ''; - } - - $html = '
'; - $html .= '

' . __( 'Download Files', 'sermon-manager-for-wordpress' ) . ''; - if ( get_wpfc_sermon_meta( 'sermon_audio' ) ) { - $html .= '' . __( 'MP3', 'sermon-manager-for-wordpress' ) . ''; - } - if ( get_wpfc_sermon_meta( 'sermon_notes' ) ) { - $html .= '' . __( 'Notes', 'sermon-manager-for-wordpress' ) . ''; - } - if ( get_wpfc_sermon_meta( 'sermon_bulletin' ) ) { - $html .= '' . __( 'Bulletin', 'sermon-manager-for-wordpress' ) . ''; - } - $html .= '

'; - $html .= '
'; - - return apply_filters( 'sm_attachments_html', $html ); -} - -// legacy function -function render_wpfc_sermon_single() { - do_action( 'sermon_single' ); -} - -// single sermon action -function wpfc_sermon_single( $return = false, $post = '' ) { - if ( $post === '' ) { - global $post; - } - - ob_start(); - ?> -
-
- -
-
-

- ', ' ' ); - the_terms( $post->ID, 'wpfc_service_type', ' (', ' ', ')' ); - ?>

-

' . __( 'Bible Text: ', 'sermon-manager-for-wordpress' ), ' | ' ); - the_terms( $post->ID, 'wpfc_preacher', '', ', ', '' ); - the_terms( $post->ID, 'wpfc_sermon_series', '

' . __( 'Series: ', 'sermon-manager-for-wordpress' ), ' ', '

' ); - ?> -

-
-
-
- - - - - - - - ID, 'wpfc_sermon_topics', '

' . __( 'Sermon Topics: ', 'sermon-manager-for-wordpress' ), ',', '

' ); ?> - -
- -
-
- -
-
-

- ', ' ' ); - the_terms( $post->ID, 'wpfc_service_type', ' (', ' ', ')' ); - ?> -

-

- ' . __( 'Bible Text: ', 'sermon-manager-for-wordpress' ), ' | ' ); - the_terms( $post->ID, 'wpfc_preacher', '', ', ', '' ); - ?> -

-

- ID, 'wpfc_sermon_series', '' . __( 'Series: ', 'sermon-manager-for-wordpress' ), ' ', '' ); ?> -

-
- -
- - - - - - -
- -
- ID, 'wpfc_sermon_series' ); - if ( $terms ) { - foreach ( $terms as $term ) { - if ( $term->description ) { - echo '
'; - echo '', - 'after_image' => '', - 'before' => ''; - echo '
'; - } - } - } -} - -/** - * Display preacher info on an individual sermon - */ -function wpfc_footer_preacher() { - global $post; - $terms = get_the_terms( $post->ID, 'wpfc_preacher' ); - if ( $terms ) { - foreach ( $terms as $term ) { - if ( $term->description ) { - echo '
'; - echo '', - 'after_image' => '', - 'before' => ''; - echo '
'; - } - } - } -} - -/** - * Build