| 开发者 | eskillsproductions |
|---|---|
| 更新时间 | 2026年6月8日 10:13 |
| PHP版本: | 8.0 及以上 |
| WordPress版本: | 7.0 |
| 版权: | GPLv2 or later |
| 版权网址: | 版权信息 |
__() so they can be translated.
Key Features
/masjid-admin/ page lets the masjid committee (administrator and the included "Bendahari Masjid" role) view donations, manage campaigns, send receipts and pull reports without learning wp-admin.[masjid_donation id="1"], [masjid_donor_wall id="1"], [masjid_donation_stats id="1"], [masjid_campaigns_list]..zip file..zip file and click Install Now.yoursite.com/masjid-admin/.[masjid_donation id="X"] where X is your campaign ID.The plugin itself is free and GPL-licensed. However, the payment gateways (ChipIn Asia, Bayarcash) charge their own transaction fees according to their pricing — please see their respective websites for current rates.
Both work well. ChipIn Asia is generally easier to onboard for smaller organizations and supports FPX, e-wallets and cards. Bayarcash is widely used by Malaysian masjids and supports FPX and DuitNow QR. You can also enable both and pick per campaign.
The current version requires at least one payment gateway to be configured because donations flow through online checkout. A pure offline / cash-receipting mode is on the roadmap.
This was a bug in versions prior to 1.1.13 — please update. Both toggles are now respected as widget-level overrides regardless of the campaign-level setting.
In two custom tables in your WordPress database — wp_masjid_donations (or your prefix) and wp_masjid_donation_logs. No data ever leaves your server except what is transmitted to your chosen payment gateway at the moment a donor checks out.
The plugin gives you the tools you need: donor anonymization, configurable data-retention period, and external resources (Google Fonts) are opt-in only. You are still responsible for your own privacy notice and for telling visitors what you collect and why.
Deactivate the plugin, then click Delete. The uninstall routine will drop the custom tables, remove the dashboard page, delete plugin options, remove custom roles and capabilities, and remove all campaign posts. This is irreversible — back up your donation data first.
Yes. All user-facing strings use the masjid-donation text domain. Drop a .mo file into wp-content/languages/plugins/ named masjid-donation-{locale}.mo.
Not yet. The current scope is one-off donations only. Recurring is on the roadmap pending gateway support.
suppress_filters => true argument from the campaign lookup in the prefix-rename migration (it is prohibited by the performance sniff and was redundant — get_posts() already defaults it internally).phpcs:ignore annotations with justifications to the dashboard-page meta lookup in Page_Provisioner::find_existing_page(). The meta_key / meta_value query runs only during activation / page-provisioning / self-heal (never on a front-end request) and returns a single row, so the SlowDBQuery warning does not apply.$wpdb queries. Per-campaign meta is now copied through get_posts() / get_post_meta() / update_post_meta() and donor phone numbers through get_users() / get_user_meta(), clearing the WordPress.DB.DirectDatabaseQuery (DirectQuery / NoCaching) warnings.$_POST reads now carry their phpcs:ignore annotations on the exact access lines, resolving the reported ValidatedSanitizedInput.InputNotSanitized (the password is intentionally passed raw to wp_signon()) and NonceVerification.Missing (the login POST is nonce-verified before the field is read) warnings.Tested up to bumped to WordPress 7.0. Trimmed the 1.1.22 upgrade notice under the 300-character limit.mdm (constants MDM_, options/meta/hooks/capabilities mdm_, the localized script objects mdmData / mdmDash / mdmBlockData) to the 8-character masjiddm prefix, satisfying the WordPress.org guideline requiring a distinct prefix of at least four characters. A one-time, non-destructive migration runs on upgrade and copies every existing setting, per-campaign meta, donor phone number and role capability from the old mdm_ keys to the new masjiddm_ keys, so existing installations keep all of their data and treasurer permissions. Legacy scheduled cron events are cleared and re-registered under the new names.<style> block, inline <script>, or a Google Fonts <link> tag. Their CSS now lives in assets/css/auth.css and the password show/hide behaviour in assets/js/auth.js; both are registered and enqueued with wp_register_style() / wp_enqueue_style() / wp_register_script() / wp_enqueue_script() and flushed into the self-contained document with wp_print_styles() / wp_print_scripts(). The optional Poppins font is enqueued (still opt-in) instead of hard-coded as a <link>./masjid-admin/) instead of the site homepage. Since they're logged out at that point, they land on the branded login page — keeping the whole experience self-contained and white-labeled.vh/dvh units, which include the area behind the browser toolbar), and the footer adds safe-area bottom padding. The "Log Keluar" button is now fully visible above the browser bar on phones. (Note: a website cannot hide the browser's own toolbar — this fix makes the menu respect it instead.)100dvh) with safe-area insets and a non-shrinking footer, so the logout button is always reachable.wp-login.php?action=lostpassword / rp) are now intercepted and rendered with the same branded card as the login page, so the whole recovery flow stays white-labeled. WordPress's own secure routines (retrieve_password(), check_password_reset_key(), reset_password()) still run underneath — only the presentation is replaced. The forgot-password response is deliberately generic to avoid revealing whether an account exists.Auth_Page_Renderer so all three screens stay visually identical./masjid-admin/) now see a custom "Selamat kembali" login card styled to match the dashboard, instead of being redirected to the WordPress wp-login.php screen. Includes an email/username field, show-password toggle, "keep me signed in for 30 days" option, a "forgot password" link, and inline error messages. Authentication is handled securely in-place via wp_signon() with nonce protection. Combined with the 1.1.20 white-labeling, treasurers never see WordPress branding./wp-admin/. This keeps the donation system looking like a standalone app rather than a WordPress site. Administrators are unaffected and keep the normal admin bar and backend. AJAX requests are still allowed so the frontend dashboard keeps working.WordPress.Security.NonceVerification.Missing warnings in Dashboard_Ajax::export_report(), assign_treasurer() and revoke_treasurer() now carry inline phpcs:ignore comments. The file-level suppression added in 1.1.18 is honoured for most handlers, but the sniff doesn't trace nonce verification through $this->check_nonce() and re-flags the three handlers where $_POST reads happen on the line immediately after the helper call. Nonce IS verified on every public handler — see the file-header note.uninstall.php — the // phpcs:enable after the schema-change block was previously unscoped, which also re-enabled the file-wide NonPrefixedVariableFound suppression and re-flagged $mdm_page_id, $mdm_admin_role, $mdm_cap, $mdm_campaigns, $mdm_campaign_id. The enable directive is now scoped to only the DirectDatabaseQuery.* / PreparedSQL.InterpolatedNotPrepared sniffs.%i identifier placeholder in $wpdb->prepare() instead of being interpolated into the SQL string (PluginCheck.Security.DirectDB.UnescapedDBParameter). Same treatment applied to column identifiers in the legacy migrate_to_utc_timestamps() routine.phpcs:disable annotations in Dashboard_Ajax moved out of the docblock into standalone comments so static analysers honour them, and extended to cover WordPress.DB.DirectDatabaseQuery.DirectQuery / NoCaching for the reports/stats endpoints (custom-table queries with no WP API equivalent).phpcs:ignore comments added to mdm_plugin() (bootstrap function), mdm_donation_rewrite_rules_flushed (hook), and the $mdm_* globals in uninstall.php. The PluginCheck sniff cannot learn that mdm is the plugin's chosen prefix; each ignore is paired with an inline note explaining why.fwrite() call in CSV export streamer now carries the same WordPress.WP.AlternativeFunctions.file_system_operations_fwrite ignore as the surrounding fopen() / fclose(). (The stream is php://output, which WP_Filesystem cannot abstract.)MDM\ (3 chars) to MasjidDM\ (8 chars) across all 35 PHP files to satisfy the 4-character minimum prefix rule. Autoloader updated. No backwards-compatibility impact — nothing outside the plugin referenced the old namespace.mdm() → mdm_plugin(). Hook name mdm_rewrite_rules_flushed → mdm_donation_rewrite_rules_flushed. Global variables in uninstall.php now carry the $mdm_ prefix.date() calls replaced with gmdate() in Donation_Manager::generate_id() and Dashboard_Ajax::dashboard_stats() so donation IDs and date filters are not subject to the WP server's runtime timezone.wp_redirect() → wp_safe_redirect() in Admin::render_dashboard_redirect() and Frontend_Dashboard::maybe_render().Campaign_CPT::save_meta() now sanitizes each $_POST field through an explicit, statically-known function (sanitize_text_field / floatval / absint) instead of a dynamic $sanitizer( ... ) dispatch, so static analysers can trace input sanitization at the call site.Dashboard_Ajax::validate_ymd_date() now accepts an already-sanitized string; every call site does sanitize_text_field( wp_unslash( $_POST[...] ?? '' ) ) inline, making the input-handling chain visible.Thank_You_Page::extract_bayarcash_return_params() now pass through sanitize_text_field() after wp_unslash() (previously unslashed but not sanitized).Dashboard_Ajax, Thank_You_Page, Donation_Manager, Activator, and Pending_Poller explaining where each suppression applies and why (nonce verification via helper methods; custom-table queries with no WP API equivalent). Three targeted phpcs:ignore lines added to Shortcodes::donation_button() / campaigns_list() where the echoed return value is already escaped inside the method.GET /wp-json/masjid-donation/v1/campaign/{id} now whitelists the fields it returns, stripping per-campaign gateway credentials (ChipIn API key / secret, Bayarcash PAT / API secret / portal key) that would otherwise have been exposed by the public endpoint. The AJAX mdm_get_campaign_data handler already whitelisted its response; the REST equivalent now does the same.$_POST values into incoming_fields; each captured field is unslashed and sanitized individually before storage.[masjid_donation ...] string and routing it through do_shortcode(). Output escaping was already correct inside the shortcode, but the new path removes the string-interpolation surface entirely.readme.txt External services section expanded to list the specific API hostnames the plugin contacts for each gateway, including sandbox endpoints (console.bayarcash-sandbox.com, api.console.bayarcash-sandbox.com) so admins know exactly which hosts are reached in test mode.style="..."; styling moved to assets/css/public.css (.mdm-block-empty).<style>, <script> and Google Fonts <link> tags are now registered through wp_enqueue_style() / wp_enqueue_script(). New asset files: assets/css/thank-you.css, assets/js/thank-you.js, assets/css/setup-wizard.css, assets/js/setup-wizard.js, assets/js/campaign-admin.js.onclick handlers replaced with data-* attributes and unobtrusive event listeners.$_SERVER (HTTP_CF_CONNECTING_IP / HTTP_X_FORWARDED_FOR / REMOTE_ADDR) now sanitizes the raw header value before parsing, and the resolved value is validated through FILTER_VALIDATE_IP so spoofed or malformed proxy headers cannot land in the database./campaign/{id}, /donor-wall/{id}, /return/{gateway}, /return, /webhook/{gateway}) now carries an explicit code comment explaining why its permission_callback is __return_true and where the actual trust boundary lives (checksum verification, IP allow-list, etc).4.4.0 → 4.5.1 (current stable upstream).chip-in.asia/terms-of-service, chip-in.asia/privacy-policy) and Bayarcash (bayarcash.com/terms-conditions/, bayarcash.com/privacy-policy/). Added a dedicated == External services == section disclosing exactly what data is sent to each third party and when.Y-m-d calendar format before reaching the database layer, instead of relying on sanitize_text_field() alone.%i placeholder in $wpdb->prepare() instead of being interpolated into the SQL string, satisfying PluginCheck.Security.DirectDB.UnescapedDBParameter.languages/ directory and shipped a masjid-donation.pot translation template so the Domain Path header points to a real folder.format parameter on the CSV export endpoint is now constrained to a known whitelist (csv) before use.assets/vendor/chart.umd.min.js) instead of loaded from a CDN, per WordPress.org plugin guideline 7 (no remote-loaded scripts).$wpdb->prepare() everywhere, cleans up transients, and force-deletes campaign meta.