{"id":384588,"date":"2026-10-12T14:39:19","date_gmt":"2026-10-12T14:39:19","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/obydullah-ironfit-core\/"},"modified":"2026-10-12T14:38:47","modified_gmt":"2026-10-12T14:38:47","slug":"obydullah-fitness-content-manager","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/obydullah-fitness-content-manager\/","author":23399590,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"7.1.3","requires":"6.2","requires_php":"8.0","requires_plugins":null,"header_name":"Obydullah Fitness Content Manager","header_author":"Shaik Obydullah","header_description":"Core functionality for fitness and personal training websites","assets_banners_color":"162033","last_updated":"2026-10-12 14:38:47","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/obydullah.com\/project\/obydullah-fitness-content-manager","header_author_uri":"https:\/\/obydullah.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":49,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"obydullah","date":"2026-10-12 14:38:47","revision":3741880}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3741878,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3741878,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3741878,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3741878,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[269,1794,6165,16809,1518],"plugin_category":[40,53],"plugin_contributors":[252589],"plugin_business_model":[],"class_list":["post-384588","plugin","type-plugin","status-publish","hentry","plugin_tags-booking","plugin_tags-custom-post-type","plugin_tags-fitness","plugin_tags-gym","plugin_tags-testimonials","plugin_category-calendar-and-events","plugin_category-ratings-and-reviews","plugin_contributors-obydullah","plugin_committers-obydullah"],"banners":{"banner":"https:\/\/ps.w.org\/obydullah-fitness-content-manager\/assets\/banner-772x250.png?rev=3741878","banner_2x":"https:\/\/ps.w.org\/obydullah-fitness-content-manager\/assets\/banner-1544x500.png?rev=3741878","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/obydullah-fitness-content-manager\/assets\/icon-128x128.png?rev=3741878","icon_2x":"https:\/\/ps.w.org\/obydullah-fitness-content-manager\/assets\/icon-256x256.png?rev=3741878","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Obydullah Fitness Content Manager holds the dynamic content for a fitness or personal training website. You manage hero slides, services, testimonials, and pricing plans in wp-admin, and booking requests arrive from your front-end form into a dedicated admin list.<\/p>\n\n<p>The content lives in the plugin, not in a theme, so it survives a theme change. Settings are stored in <code>wp_options<\/code> rather than <code>theme_mod()<\/code> for the same reason.<\/p>\n\n<h4>What it does<\/h4>\n\n<ul>\n<li><strong>Hero slides<\/strong> \u2014 a private post type for the homepage carousel. Each slide carries a subtitle or badge, description, and two buttons with their own text and URL.<\/li>\n<li><strong>Services<\/strong> \u2014 a private post type for your service offerings. Title and description come from the post itself, plus an icon field that accepts an emoji or a Font Awesome class.<\/li>\n<li><strong>Testimonials<\/strong> \u2014 a private post type for client reviews. Each entry has a quote, a role or result label, a 1 to 5 star rating, and a result caption.<\/li>\n<li><strong>Pricing plans<\/strong> \u2014 a private post type for pricing cards, with price, billing period, a newline-separated feature list, a custom button label, and a flag to highlight one plan as the popular choice.<\/li>\n<li><strong>Bookings<\/strong> \u2014 front-end form submissions stored in a custom database table. The admin list supports search by name or email, per-status filters with counts, pagination, inline status changes, and deletion.<\/li>\n<li><strong>Admin dashboard<\/strong> \u2014 a single card grid under one top-level menu, linking to each content type and to settings.<\/li>\n<li><strong>Site settings<\/strong> \u2014 contact details, social links, two about paragraphs, coach name and title, certifications, specialties, three stat blocks, and an aggregate rating. All stored in <code>wp_options<\/code>.<\/li>\n<\/ul>\n\n<h4>Design choices<\/h4>\n\n<ul>\n<li><strong>Content outranks posts.<\/strong> All four content types are private custom post types, so they inherit WordPress revisions, media handling, scheduling, and the block editor. Featured images work as expected.<\/li>\n<li><strong>Bookings use a custom table.<\/strong> Form submissions are high-volume write-once data with no need for revisions or taxonomy, so they go to a <code>{prefix}ofcm_bookings<\/code> table instead of the posts table. This keeps the posts table clean and booking queries fast as submissions accumulate.<\/li>\n<li><strong>No external services.<\/strong> The plugin loads no remote fonts, scripts, or styles, and makes no outbound HTTP requests. It sends no usage or telemetry data.<\/li>\n<li><strong>Prefixed everything.<\/strong> Functions, hooks, meta keys, options, nonces, and the custom table all use the <code>ofcm_<\/code> prefix, so the plugin cannot collide with your theme or another plugin.<\/li>\n<li><strong>Admin-only content.<\/strong> Every post type registers with <code>public =&gt; false<\/code>. Nothing added through this plugin is publicly queryable, and the booking table is never exposed to the front end.<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Go to <strong>Plugins \u2192 Add New<\/strong>, search for \"Obydullah Fitness Content Manager\", or upload the plugin zip.<\/li>\n<li>Click <strong>Install Now<\/strong>, then <strong>Activate<\/strong>.<\/li>\n<li>Activation creates the <code>{prefix}ofcm_bookings<\/code> database table.<\/li>\n<li>Open <strong>Obydullah Fitness Content Manager<\/strong> and add content using the dashboard cards.<\/li>\n<li>Set your contact and about details under <strong>Obydullah Fitness Content Manager \u2192 Site Settings<\/strong>.<\/li>\n<\/ol>\n\n<h4>Using the booking form<\/h4>\n\n<p>The booking form is a <code>fetch()<\/code> request to <code>admin-ajax.php<\/code>. Your front-end form needs to append two fields:<\/p>\n\n<ul>\n<li><code>action<\/code> with the value <code>ofcm_submit_booking<\/code><\/li>\n<li><code>nonce<\/code> from <code>wp_create_nonce( 'ofcm_booking_nonce' )<\/code>, passed to your script with <code>wp_localize_script()<\/code><\/li>\n<\/ul>\n\n<p>The handler accepts <code>name<\/code>, <code>email<\/code>, <code>phone<\/code>, <code>goal<\/code>, and <code>message<\/code>. Name and email are required; everything else is optional. The response is a JSON object \u2014 on success the message is in the <code>data<\/code> property of the payload, and on failure the payload is an error with a <code>data<\/code> string explaining what went wrong.<\/p>\n\n<h4>For theme developers<\/h4>\n\n<p>Content is read with the standard WordPress APIs. Query the post types directly, or read meta with the prefixed keys:<\/p>\n\n<ul>\n<li><code>ofcm_hero_slide<\/code> \u2014 <code>ofcm_slide_subtitle<\/code>, <code>ofcm_slide_description<\/code>, <code>ofcm_slide_btn_text<\/code>, <code>ofcm_slide_btn_url<\/code>, <code>ofcm_slide_btn2_text<\/code>, <code>ofcm_slide_btn2_url<\/code><\/li>\n<li><code>ofcm_service<\/code> \u2014 <code>ofcm_service_icon<\/code><\/li>\n<li><code>ofcm_testimonial<\/code> \u2014 <code>ofcm_testimonial_quote<\/code>, <code>ofcm_testimonial_role<\/code>, <code>ofcm_testimonial_rating<\/code>, <code>ofcm_testimonial_result<\/code><\/li>\n<li><code>ofcm_pricing<\/code> \u2014 <code>ofcm_pricing_price<\/code>, <code>ofcm_pricing_period<\/code>, <code>ofcm_pricing_features<\/code>, <code>ofcm_pricing_popular<\/code>, <code>ofcm_pricing_btn_text<\/code><\/li>\n<\/ul>\n\n<p>Settings are read with <code>get_option()<\/code> using keys such as <code>ofcm_contact_email<\/code>, <code>ofcm_social_instagram<\/code>, <code>ofcm_about_coach_name<\/code>, and <code>ofcm_about_stat1_number<\/code>.<\/p>\n\n<p>Bookings are read from the table with <code>$wpdb<\/code>. Always use <code>prepare()<\/code>:<\/p>\n\n<pre><code>$rows = $wpdb-&gt;get_results( $wpdb-&gt;prepare( \"SELECT id, name, email, status FROM {$table} WHERE status = %s ORDER BY created_at DESC LIMIT %d\", $status, 20 ) );\n<\/code><\/pre>\n\n<!--section=faq-->\n<dl>\n<dt id=\"where%20is%20my%20data%20stored%3F\"><h3>Where is my data stored?<\/h3><\/dt>\n<dd><p>In your own WordPress database on your own hosting. Content types use custom post types and their meta, settings use <code>wp_options<\/code>, and bookings use a custom table prefixed with your WordPress table prefix. Nothing is sent anywhere else.<\/p><\/dd>\n<dt id=\"why%20are%20bookings%20in%20a%20table%20instead%20of%20a%20post%20type%3F\"><h3>Why are bookings in a table instead of a post type?<\/h3><\/dt>\n<dd><p>Form submissions are write-once records that never need revisions, categories, or scheduled publishing. Storing them in a custom table keeps the posts table from filling with thousands of low-value entries and keeps booking queries fast regardless of how many submissions you have.<\/p><\/dd>\n<dt id=\"can%20i%20import%20the%20bookings%20i%20already%20have%3F\"><h3>Can I import the bookings I already have?<\/h3><\/dt>\n<dd><p>Not from inside the plugin. The table is created fresh on activation. If you are moving from a site where bookings were stored as a custom post type, you will need to copy those rows into the new table yourself, or re-enter them.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20send%20anything%20to%20an%20external%20service%3F\"><h3>Does the plugin send anything to an external service?<\/h3><\/dt>\n<dd><p>No. It loads no remote fonts, scripts, or styles, makes no outbound HTTP requests, and collects no usage or telemetry data.<\/p><\/dd>\n<dt id=\"will%20deleting%20the%20plugin%20delete%20my%20data%3F\"><h3>Will deleting the plugin delete my data?<\/h3><\/dt>\n<dd><p>No. Removing the plugin leaves your content, settings, and the bookings table in place. Delete the <code>{prefix}ofcm_bookings<\/code> table and the <code>ofcm_<\/code> options yourself if you want a clean slate.<\/p><\/dd>\n<dt id=\"do%20i%20need%20a%20particular%20theme%3F\"><h3>Do I need a particular theme?<\/h3><\/dt>\n<dd><p>No. The plugin is theme-independent and works with any theme. It provides no front-end output on its own \u2014 your theme renders the content.<\/p><\/dd>\n<dt id=\"can%20i%20translate%20the%20admin%20labels%3F\"><h3>Can I translate the admin labels?<\/h3><\/dt>\n<dd><p>Yes. All strings use the <code>obydullah-fitness-content-manager<\/code> text domain. A translation file in the plugin's <code>languages<\/code> folder is picked up automatically.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>Four private custom post types: Hero Slides, Services, Testimonials, and Pricing Plans.<\/li>\n<li>Bookings stored in a custom <code>{prefix}ofcm_bookings<\/code> table, created with <code>dbDelta()<\/code> on activation.<\/li>\n<li>Bookings admin list with search, per-status filters with counts, pagination, inline status updates, and deletion.<\/li>\n<li>AJAX booking form handler with nonce verification and field-level sanitization.<\/li>\n<li>Admin dashboard with a card grid linking to each content type and to settings.<\/li>\n<li>Site settings for contact details, social links, about content, stats, and rating, stored in <code>wp_options<\/code>.<\/li>\n<li>Meta boxes with nonce verification, capability checks, and field-level sanitization.<\/li>\n<\/ul>","raw_excerpt":"Content management for a fitness or personal training site: hero slides, services, testimonials, pricing plans, and booking requests.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/384588","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=384588"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/obydullah"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=384588"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=384588"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=384588"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=384588"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=384588"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=384588"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}