/** * @file Contains all dynamic functionality needed on post and term pages. * * @output wp-admin/js/post.js */ /* global ajaxurl, wpAjax, postboxes, pagenow, tinymce, alert, deleteUserSetting, ClipboardJS */ /* global theList:true, theExtraList:true, getUserSetting, setUserSetting, commentReply, commentsBox */ /* global WPSetThumbnailHTML, wptitlehint */ // Backward compatibility: prevent fatal errors. window.makeSlugeditClickable = window.editPermalink = function(){}; // Make sure the wp object exists. window.wp = window.wp || {}; ( function( $ ) { var titleHasFocus = false, __ = wp.i18n.__; /** * Control loading of comments on the post and term edit pages. * * @type {{st: number, get: commentsBox.get, load: commentsBox.load}} * * @namespace commentsBox */ window.commentsBox = { // Comment offset to use when fetching new comments. st : 0, /** * Fetch comments using Ajax and display them in the box. * * @memberof commentsBox * * @param {number} total Total number of comments for this post. * @param {number} num Optional. Number of comments to fetch, defaults to 20. * @return {boolean} Always returns false. */ get : function(total, num) { var st = this.st, data; if ( ! num ) num = 20; this.st += num; this.total = total; $( '#commentsdiv .spinner' ).addClass( 'is-active' ); data = { 'action' : 'get-comments', 'mode' : 'single', '_ajax_nonce' : $('#add_comment_nonce').val(), 'p' : $('#post_ID').val(), 'start' : st, 'number' : num }; $.post( ajaxurl, data, function(r) { r = wpAjax.parseAjaxResponse(r); $('#commentsdiv .widefat').show(); $( '#commentsdiv .spinner' ).removeClass( 'is-active' ); if ( 'object' == typeof r && r.responses[0] ) { $('#the-comment-list').append( r.responses[0].data ); theList = theExtraList = null; $( 'a[className*=\':\']' ).off(); // If the offset is over the total number of comments we cannot fetch any more, so hide the button. if ( commentsBox.st > commentsBox.total ) $('#show-comments').hide(); else $('#show-comments').show().children('a').text( __( 'Show more comments' ) ); return; } else if ( 1 == r ) { $('#show-comments').text( __( 'No more comments found.' ) ); return; } $('#the-comment-list').append(''+wpAjax.broken+''); } ); return false; }, /** * Load the next batch of comments. * * @memberof commentsBox * * @param {number} total Total number of comments to load. */ load: function(total){ this.st = jQuery('#the-comment-list tr.comment:visible').length; this.get(total); } }; /** * Overwrite the content of the Featured Image postbox * * @param {string} html New HTML to be displayed in the content area of the postbox. * * @global */ window.WPSetThumbnailHTML = function(html){ $('.inside', '#postimagediv').html(html); }; /** * Set the Image ID of the Featured Image * * @param {number} id The post_id of the image to use as Featured Image. * * @global */ window.WPSetThumbnailID = function(id){ var field = $('input[value="_thumbnail_id"]', '#list-table'); if ( field.length > 0 ) { $('#meta\\[' + field.attr('id').match(/[0-9]+/) + '\\]\\[value\\]').text(id); } }; /** * Remove the Featured Image * * @param {string} nonce Nonce to use in the request. * * @global */ window.WPRemoveThumbnail = function(nonce){ $.post( ajaxurl, { action: 'set-post-thumbnail', post_id: $( '#post_ID' ).val(), thumbnail_id: -1, _ajax_nonce: nonce, cookie: encodeURIComponent( document.cookie ) }, /** * Handle server response * * @param {string} str Response, will be '0' when an error occurred otherwise contains link to add Featured Image. */ function(str){ if ( str == '0' ) { alert( __( 'Could not set that as the thumbnail image. Try a different attachment.' ) ); } else { WPSetThumbnailHTML(str); } } ); }; /** * Heartbeat locks. * * Used to lock editing of an object by only one user at a time. * * When the user does not send a heartbeat in a heartbeat-time * the user is no longer editing and another user can start editing. */ $(document).on( 'heartbeat-send.refresh-lock', function( e, data ) { var lock = $('#active_post_lock').val(), post_id = $('#post_ID').val(), send = {}; if ( ! post_id || ! $('#post-lock-dialog').length ) return; send.post_id = post_id; if ( lock ) send.lock = lock; data['wp-refresh-post-lock'] = send; }).on( 'heartbeat-tick.refresh-lock', function( e, data ) { // Post locks: update the lock string or show the dialog if somebody has taken over editing. var received, wrap, avatar; if ( data['wp-refresh-post-lock'] ) { received = data['wp-refresh-post-lock']; if ( received.lock_error ) { // Show "editing taken over" message. wrap = $('#post-lock-dialog'); if ( wrap.length && ! wrap.is(':visible') ) { if ( wp.autosave ) { // Save the latest changes and disable. $(document).one( 'heartbeat-tick', function() { wp.autosave.server.suspend(); wrap.removeClass('saving').addClass('saved'); $(window).off( 'beforeunload.edit-post' ); }); wrap.addClass('saving'); wp.autosave.server.triggerSave(); } if ( received.lock_error.avatar_src ) { avatar = $( '', { 'class': 'avatar avatar-64 photo', width: 64, height: 64, alt: '', src: received.lock_error.avatar_src, srcset: received.lock_error.avatar_src_2x ? received.lock_error.avatar_src_2x + ' 2x' : undefined } ); wrap.find('div.post-locked-avatar').empty().append( avatar ); } wrap.show().find('.currently-editing').text( received.lock_error.text ); wrap.find('.wp-tab-first').trigger( 'focus' ); } } else if ( received.new_lock ) { $('#active_post_lock').val( received.new_lock ); } } }).on( 'before-autosave.update-post-slug', function() { titleHasFocus = document.activeElement && document.activeElement.id === 'title'; }).on( 'after-autosave.update-post-slug', function() { /* * Create slug area only if not already there * and the title field was not focused (user was not typing a title) when autosave ran. */ if ( ! $('#edit-slug-box > *').length && ! titleHasFocus ) { $.post( ajaxurl, { action: 'sample-permalink', post_id: $('#post_ID').val(), new_title: $('#title').val(), samplepermalinknonce: $('#samplepermalinknonce').val() }, function( data ) { if ( data != '-1' ) { $('#edit-slug-box').html(data); } } ); } }); }(jQuery)); /** * Heartbeat refresh nonces. */ (function($) { var check, timeout; /** * Only allow to check for nonce refresh every 30 seconds. */ function schedule() { check = false; window.clearTimeout( timeout ); timeout = window.setTimeout( function(){ check = true; }, 300000 ); } $( function() { schedule(); }).on( 'heartbeat-send.wp-refresh-nonces', function( e, data ) { var post_id, $authCheck = $('#wp-auth-check-wrap'); if ( check || ( $authCheck.length && ! $authCheck.hasClass( 'hidden' ) ) ) { if ( ( post_id = $('#post_ID').val() ) && $('#_wpnonce').val() ) { data['wp-refresh-post-nonces'] = { post_id: post_id }; } } }).on( 'heartbeat-tick.wp-refresh-nonces', function( e, data ) { var nonces = data['wp-refresh-post-nonces']; if ( nonces ) { schedule(); if ( nonces.replace ) { $.each( nonces.replace, function( selector, value ) { $( '#' + selector ).val( value ); }); } if ( nonces.heartbeatNonce ) window.heartbeatSettings.nonce = nonces.heartbeatNonce; } }); }(jQuery)); /** * All post and postbox controls and functionality. */ jQuery( function($) { var stamp, visibility, $submitButtons, updateVisibility, updateText, $textarea = $('#content'), $document = $(document), postId = $('#post_ID').val() || 0, $submitpost = $('#submitpost'), releaseLock = true, $postVisibilitySelect = $('#post-visibility-select'), $timestampdiv = $('#timestampdiv'), $postStatusSelect = $('#post-status-select'), isMac = window.navigator.platform ? window.navigator.platform.indexOf( 'Mac' ) !== -1 : false, copyAttachmentURLClipboard = new ClipboardJS( '.copy-attachment-url.edit-media' ), copyAttachmentURLSuccessTimeout, __ = wp.i18n.__, _x = wp.i18n._x; postboxes.add_postbox_toggles(pagenow); /* * Clear the window name. Otherwise if this is a former preview window where the user navigated to edit another post, * and the first post is still being edited, clicking Preview there will use this window to show the preview. */ window.name = ''; // Post locks: contain focus inside the dialog. If the dialog is shown, focus the first item. $('#post-lock-dialog .notification-dialog').on( 'keydown', function(e) { // Don't do anything when [Tab] is pressed. if ( e.which != 9 ) return; var target = $(e.target); // [Shift] + [Tab] on first tab cycles back to last tab. if ( target.hasClass('wp-tab-first') && e.shiftKey ) { $(this).find('.wp-tab-last').trigger( 'focus' ); e.preventDefault(); // [Tab] on last tab cycles back to first tab. } else if ( target.hasClass('wp-tab-last') && ! e.shiftKey ) { $(this).find('.wp-tab-first').trigger( 'focus' ); e.preventDefault(); } }).filter(':visible').find('.wp-tab-first').trigger( 'focus' ); // Set the heartbeat interval to 10 seconds if post lock dialogs are enabled. if ( wp.heartbeat && $('#post-lock-dialog').length ) { wp.heartbeat.interval( 10 ); } // The form is being submitted by the user. $submitButtons = $submitpost.find( ':submit, a.submitdelete, #post-preview' ).on( 'click.edit-post', function( event ) { var $button = $(this); if ( $button.hasClass('disabled') ) { event.preventDefault(); return; } if ( $button.hasClass('submitdelete') || $button.is( '#post-preview' ) ) { return; } // The form submission can be blocked from JS or by using HTML 5.0 validation on some fields. // Run this only on an actual 'submit'. $('form#post').off( 'submit.edit-post' ).on( 'submit.edit-post', function( event ) { if ( event.isDefaultPrevented() ) { return; } // Stop auto save. if ( wp.autosave ) { wp.autosave.server.suspend(); } if ( typeof commentReply !== 'undefined' ) { /* * Warn the user they have an unsaved comment before submitting * the post data for update. */ if ( ! commentReply.discardCommentChanges() ) { return false; } /* * Close the comment edit/reply form if open to stop the form * action from interfering with the post's form action. */ commentReply.close(); } releaseLock = false; $(window).off( 'beforeunload.edit-post' ); $submitButtons.addClass( 'disabled' ); if ( $button.attr('id') === 'publish' ) { $submitpost.find( '#major-publishing-actions .spinner' ).addClass( 'is-active' ); } else { $submitpost.find( '#minor-publishing .spinner' ).addClass( 'is-active' ); } }); }); // Submit the form saving a draft or an autosave, and show a preview in a new tab. $('#post-preview').on( 'click.post-preview', function( event ) { var $this = $(this), $form = $('form#post'), $previewField = $('input#wp-preview'), target = $this.attr('target') || 'wp-preview', ua = navigator.userAgent.toLowerCase(); event.preventDefault(); if ( $this.hasClass('disabled') ) { return; } if ( wp.autosave ) { wp.autosave.server.tempBlockSave(); } $previewField.val('dopreview'); $form.attr( 'target', target ).trigger( 'submit' ).attr( 'target', '' ); // Workaround for WebKit bug preventing a form submitting twice to the same action. // https://bugs.webkit.org/show_bug.cgi?id=28633 if ( ua.indexOf('safari') !== -1 && ua.indexOf('chrome') === -1 ) { $form.attr( 'action', function( index, value ) { return value + '?t=' + ( new Date() ).getTime(); }); } $previewField.val(''); }); // Auto save new posts after a title is typed. if ( $( '#auto_draft' ).val() ) { $( '#title' ).on( 'blur', function() { var cancel; if ( ! this.value || $('#edit-slug-box > *').length ) { return; } // Cancel the auto save when the blur was triggered by the user submitting the form. $('form#post').one( 'submit', function() { cancel = true; }); window.setTimeout( function() { if ( ! cancel && wp.autosave ) { wp.autosave.server.triggerSave(); } }, 200 ); }); } $document.on( 'autosave-disable-buttons.edit-post', function() { $submitButtons.addClass( 'disabled' ); }).on( 'autosave-enable-buttons.edit-post', function() { if ( ! wp.heartbeat || ! wp.heartbeat.hasConnectionError() ) { $submitButtons.removeClass( 'disabled' ); } }).on( 'before-autosave.edit-post', function() { $( '.autosave-message' ).text( __( 'Saving Draft…' ) ); }).on( 'after-autosave.edit-post', function( event, data ) { $( '.autosave-message' ).text( data.message ); if ( $( document.body ).hasClass( 'post-new-php' ) ) { $( '.submitbox .submitdelete' ).show(); } }); /* * When the user is trying to load another page, or reloads current page * show a confirmation dialog when there are unsaved changes. */ $( window ).on( 'beforeunload.edit-post', function( event ) { var editor = window.tinymce && window.tinymce.get( 'content' ); var changed = false; if ( wp.autosave ) { changed = wp.autosave.server.postChanged(); } else if ( editor ) { changed = ( ! editor.isHidden() && editor.isDirty() ); } if ( changed ) { event.preventDefault(); // The return string is needed for browser compat. // See https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event. return __( 'The changes you made will be lost if you navigate away from this page.' ); } }).on( 'pagehide.edit-post', function( event ) { if ( ! releaseLock ) { return; } /* * Unload is triggered (by hand) on removing the Thickbox iframe. * Make sure we process only the main document unload. */ if ( event.target && event.target.nodeName != '#document' ) { return; } var postID = $('#post_ID').val(); var postLock = $('#active_post_lock').val(); if ( ! postID || ! postLock ) { return; } var data = { action: 'wp-remove-post-lock', _wpnonce: $('#_wpnonce').val(), post_ID: postID, active_post_lock: postLock }; if ( window.FormData && window.navigator.sendBeacon ) { var formData = new window.FormData(); $.each( data, function( key, value ) { formData.append( key, value ); }); if ( window.navigator.sendBeacon( ajaxurl, formData ) ) { return; } } // Fall back to a synchronous POST request. // See https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon $.post({ async: false, data: data, url: ajaxurl }); }); // Multiple taxonomies. if ( $('#tagsdiv-post_tag').length ) { window.tagBox && window.tagBox.init(); } else { $('.meta-box-sortables').children('div.postbox').each(function(){ if ( this.id.indexOf('tagsdiv-') === 0 ) { window.tagBox && window.tagBox.init(); return false; } }); } // Handle categories. $('.categorydiv').each( function(){ var this_id = $(this).attr('id'), catAddBefore, catAddAfter, taxonomyParts, taxonomy, settingName; taxonomyParts = this_id.split('-'); taxonomyParts.shift(); taxonomy = taxonomyParts.join('-'); settingName = taxonomy + '_tab'; if ( taxonomy == 'category' ) { settingName = 'cats'; } // @todo Move to jQuery 1.3+, support for multiple hierarchical taxonomies, see wp-lists.js. $('a', '#' + taxonomy + '-tabs').on( 'click', function( e ) { e.preventDefault(); var t = $(this).attr('href'); $(this).parent().addClass('tabs').siblings('li').removeClass('tabs'); $('#' + taxonomy + '-tabs').siblings('.tabs-panel').hide(); $(t).show(); if ( '#' + taxonomy + '-all' == t ) { deleteUserSetting( settingName ); } else { setUserSetting( settingName, 'pop' ); } }); if ( getUserSetting( settingName ) ) $('a[href="#' + taxonomy + '-pop"]', '#' + taxonomy + '-tabs').trigger( 'click' ); // Add category button controls. $('#new' + taxonomy).one( 'focus', function() { $( this ).val( '' ).removeClass( 'form-input-tip' ); }); // On [Enter] submit the taxonomy. $('#new' + taxonomy).on( 'keypress', function(event){ if( 13 === event.keyCode ) { event.preventDefault(); $('#' + taxonomy + '-add-submit').trigger( 'click' ); } }); // After submitting a new taxonomy, re-focus the input field. $('#' + taxonomy + '-add-submit').on( 'click', function() { $('#new' + taxonomy).trigger( 'focus' ); }); /** * Before adding a new taxonomy, disable submit button. * * @param {Object} s Taxonomy object which will be added. * * @return {Object} */ catAddBefore = function( s ) { if ( !$('#new'+taxonomy).val() ) { return false; } s.data += '&' + $( ':checked', '#'+taxonomy+'checklist' ).serialize(); $( '#' + taxonomy + '-add-submit' ).prop( 'disabled', true ); return s; }; /** * Re-enable submit button after a taxonomy has been added. * * Re-enable submit button. * If the taxonomy has a parent place the taxonomy underneath the parent. * * @param {Object} r Response. * @param {Object} s Taxonomy data. * * @return {void} */ catAddAfter = function( r, s ) { var sup, drop = $('#new'+taxonomy+'_parent'); $( '#' + taxonomy + '-add-submit' ).prop( 'disabled', false ); if ( 'undefined' != s.parsed.responses[0] && (sup = s.parsed.responses[0].supplemental.newcat_parent) ) { drop.before(sup); drop.remove(); } }; $('#' + taxonomy + 'checklist').wpList({ alt: '', response: taxonomy + '-ajax-response', addBefore: catAddBefore, addAfter: catAddAfter }); // Add new taxonomy button toggles input form visibility. $('#' + taxonomy + '-add-toggle').on( 'click', function( e ) { e.preventDefault(); $('#' + taxonomy + '-adder').toggleClass( 'wp-hidden-children' ); $('a[href="#' + taxonomy + '-all"]', '#' + taxonomy + '-tabs').trigger( 'click' ); $('#new'+taxonomy).trigger( 'focus' ); }); // Sync checked items between "All {taxonomy}" and "Most used" lists. $('#' + taxonomy + 'checklist, #' + taxonomy + 'checklist-pop').on( 'click', 'li.popular-category > label input[type="checkbox"]', function() { var t = $(this), c = t.is(':checked'), id = t.val(); if ( id && t.parents('#taxonomy-'+taxonomy).length ) { // Fixed for ticket #62504. See https://core.trac.wordpress.org/ticket/62504. $('input#in-' + taxonomy + '-' + id + ', input[id^="in-' + taxonomy + '-' + id + '-"]').prop('checked', c); $('input#in-popular-' + taxonomy + '-' + id).prop('checked', c); } } ); }); // End cats. // Custom Fields postbox. if ( $('#postcustom').length ) { $( '#the-list' ).wpList( { /** * Add current post_ID to request to fetch custom fields * * @ignore * * @param {Object} s Request object. * * @return {Object} Data modified with post_ID attached. */ addBefore: function( s ) { s.data += '&post_id=' + $('#post_ID').val(); return s; }, /** * Show the listing of custom fields after fetching. * * @ignore */ addAfter: function() { $('table#list-table').show(); } }); } /* * Publish Post box (#submitdiv) */ if ( $('#submitdiv').length ) { stamp = $('#timestamp').html(); visibility = $('#post-visibility-display').html(); /** * When the visibility of a post changes sub-options should be shown or hidden. * * @ignore * * @return {void} */ updateVisibility = function() { // Show sticky for public posts. if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) { $('#sticky').prop('checked', false); $('#sticky-span').hide(); } else { $('#sticky-span').show(); } // Show password input field for password protected post. if ( $postVisibilitySelect.find('input:radio:checked').val() != 'password' ) { $('#password-span').hide(); } else { $('#password-span').show(); } }; /** * Make sure all labels represent the current settings. * * @ignore * * @return {boolean} False when an invalid timestamp has been selected, otherwise True. */ updateText = function() { if ( ! $timestampdiv.length ) return true; var attemptedDate, originalDate, currentDate, publishOn, postStatus = $('#post_status'), optPublish = $('option[value="publish"]', postStatus), aa = $('#aa').val(), mm = $('#mm').val(), jj = $('#jj').val(), hh = $('#hh').val(), mn = $('#mn').val(); attemptedDate = new Date( aa, mm - 1, jj, hh, mn ); originalDate = new Date( $('#hidden_aa').val(), $('#hidden_mm').val() -1, $('#hidden_jj').val(), $('#hidden_hh').val(), $('#hidden_mn').val() ); currentDate = new Date( $('#cur_aa').val(), $('#cur_mm').val() -1, $('#cur_jj').val(), $('#cur_hh').val(), $('#cur_mn').val() ); // Catch unexpected date problems. if ( attemptedDate.getFullYear() != aa || (1 + attemptedDate.getMonth()) != mm || attemptedDate.getDate() != jj || attemptedDate.getMinutes() != mn ) { $timestampdiv.find('.timestamp-wrap').addClass('form-invalid'); return false; } else { $timestampdiv.find('.timestamp-wrap').removeClass('form-invalid'); } // Determine what the publish should be depending on the date and post status. if ( attemptedDate > currentDate ) { publishOn = __( 'Schedule for:' ); $('#publish').val( _x( 'Schedule', 'post action/button label' ) ); } else if ( attemptedDate <= currentDate && $('#original_post_status').val() != 'publish' ) { publishOn = __( 'Publish on:' ); $('#publish').val( __( 'Publish' ) ); } else { publishOn = __( 'Published on:' ); $('#publish').val( __( 'Update' ) ); } // If the date is the same, set it to trigger update events. if ( originalDate.toUTCString() == attemptedDate.toUTCString() ) { // Re-set to the current value. $('#timestamp').html(stamp); } else { $('#timestamp').html( '\n' + publishOn + ' ' + // translators: 1: Month, 2: Day, 3: Year, 4: Hour, 5: Minute. __( '%1$s %2$s, %3$s at %4$s:%5$s' ) .replace( '%1$s', $( 'option[value="' + mm + '"]', '#mm' ).attr( 'data-text' ) ) .replace( '%2$s', parseInt( jj, 10 ) ) .replace( '%3$s', aa ) .replace( '%4$s', ( '00' + hh ).slice( -2 ) ) .replace( '%5$s', ( '00' + mn ).slice( -2 ) ) + ' ' ); } // Add "privately published" to post status when applies. if ( $postVisibilitySelect.find('input:radio:checked').val() == 'private' ) { $('#publish').val( __( 'Update' ) ); if ( 0 === optPublish.length ) { postStatus.append(''); } else { optPublish.html( __( 'Privately Published' ) ); } $('option[value="publish"]', postStatus).prop('selected', true); $('#misc-publishing-actions .edit-post-status').hide(); } else { if ( $('#original_post_status').val() == 'future' || $('#original_post_status').val() == 'draft' ) { if ( optPublish.length ) { optPublish.remove(); postStatus.val($('#hidden_post_status').val()); } } else { optPublish.html( __( 'Published' ) ); } if ( postStatus.is(':hidden') ) $('#misc-publishing-actions .edit-post-status').show(); } // Update "Status:" to currently selected status. $('#post-status-display').text( // Remove any potential tags from post status text. wp.sanitize.stripTagsAndEncodeText( $('option:selected', postStatus).text() ) ); // Show or hide the "Save Draft" button. if ( $('option:selected', postStatus).val() == 'private' || $('option:selected', postStatus).val() == 'publish' ) { $('#save-post').hide(); } else { $('#save-post').show(); if ( $('option:selected', postStatus).val() == 'pending' ) { $('#save-post').show().val( __( 'Save as Pending' ) ); } else { $('#save-post').show().val( __( 'Save Draft' ) ); } } return true; }; // Show the visibility options and hide the toggle button when opened. $( '#visibility .edit-visibility').on( 'click', function( e ) { e.preventDefault(); if ( $postVisibilitySelect.is(':hidden') ) { updateVisibility(); $postVisibilitySelect.slideDown( 'fast', function() { $postVisibilitySelect.find( 'input[type="radio"]' ).first().trigger( 'focus' ); } ); $(this).hide(); } }); // Cancel visibility selection area and hide it from view. $postVisibilitySelect.find('.cancel-post-visibility').on( 'click', function( event ) { $postVisibilitySelect.slideUp('fast'); $('#visibility-radio-' + $('#hidden-post-visibility').val()).prop('checked', true); $('#post_password').val($('#hidden-post-password').val()); $('#sticky').prop('checked', $('#hidden-post-sticky').prop('checked')); $('#post-visibility-display').html(visibility); $('#visibility .edit-visibility').show().trigger( 'focus' ); updateText(); event.preventDefault(); }); // Set the selected visibility as current. $postVisibilitySelect.find('.save-post-visibility').on( 'click', function( event ) { // Crazyhorse branch - multiple OK cancels. var visibilityLabel = '', selectedVisibility = $postVisibilitySelect.find('input:radio:checked').val(); $postVisibilitySelect.slideUp('fast'); $('#visibility .edit-visibility').show().trigger( 'focus' ); updateText(); if ( 'public' !== selectedVisibility ) { $('#sticky').prop('checked', false); } switch ( selectedVisibility ) { case 'public': visibilityLabel = $( '#sticky' ).prop( 'checked' ) ? __( 'Public, Sticky' ) : __( 'Public' ); break; case 'private': visibilityLabel = __( 'Private' ); break; case 'password': visibilityLabel = __( 'Password Protected' ); break; } $('#post-visibility-display').text( visibilityLabel ); event.preventDefault(); }); // When the selection changes, update labels. $postVisibilitySelect.find('input:radio').on( 'change', function() { updateVisibility(); }); // Edit publish time click. $timestampdiv.siblings('a.edit-timestamp').on( 'click', function( event ) { if ( $timestampdiv.is( ':hidden' ) ) { $timestampdiv.slideDown( 'fast', function() { $( 'input, select', $timestampdiv.find( '.timestamp-wrap' ) ).first().trigger( 'focus' ); } ); $(this).hide(); } event.preventDefault(); }); // Cancel editing the publish time and hide the settings. $timestampdiv.find('.cancel-timestamp').on( 'click', function( event ) { $timestampdiv.slideUp('fast').siblings('a.edit-timestamp').show().trigger( 'focus' ); $('#mm').val($('#hidden_mm').val()); $('#jj').val($('#hidden_jj').val()); $('#aa').val($('#hidden_aa').val()); $('#hh').val($('#hidden_hh').val()); $('#mn').val($('#hidden_mn').val()); updateText(); event.preventDefault(); }); // Save the changed timestamp. $timestampdiv.find('.save-timestamp').on( 'click', function( event ) { // Crazyhorse branch - multiple OK cancels. if ( updateText() ) { $timestampdiv.slideUp('fast'); $timestampdiv.siblings('a.edit-timestamp').show().trigger( 'focus' ); } event.preventDefault(); }); // Cancel submit when an invalid timestamp has been selected. $('#post').on( 'submit', function( event ) { if ( ! updateText() ) { event.preventDefault(); $timestampdiv.show(); if ( wp.autosave ) { wp.autosave.enableButtons(); } $( '#publishing-action .spinner' ).removeClass( 'is-active' ); } }); // Post Status edit click. $postStatusSelect.siblings('a.edit-post-status').on( 'click', function( event ) { if ( $postStatusSelect.is( ':hidden' ) ) { $postStatusSelect.slideDown( 'fast', function() { $postStatusSelect.find('select').trigger( 'focus' ); } ); $(this).hide(); } event.preventDefault(); }); // Save the Post Status changes and hide the options. $postStatusSelect.find('.save-post-status').on( 'click', function( event ) { $postStatusSelect.slideUp( 'fast' ).siblings( 'a.edit-post-status' ).show().trigger( 'focus' ); updateText(); event.preventDefault(); }); // Cancel Post Status editing and hide the options. $postStatusSelect.find('.cancel-post-status').on( 'click', function( event ) { $postStatusSelect.slideUp( 'fast' ).siblings( 'a.edit-post-status' ).show().trigger( 'focus' ); $('#post_status').val( $('#hidden_post_status').val() ); updateText(); event.preventDefault(); }); } /** * Handle the editing of the post_name. Create the required HTML elements and * update the changes via Ajax. * * @global * * @return {void} */ function editPermalink() { var i, slug_value, slug_label, $el, revert_e, c = 0, real_slug = $('#post_name'), revert_slug = real_slug.val(), permalink = $( '#sample-permalink' ), permalinkOrig = permalink.html(), permalinkInner = $( '#sample-permalink a' ).html(), buttons = $('#edit-slug-buttons'), buttonsOrig = buttons.html(), full = $('#editable-post-name-full'); // Deal with Twemoji in the post-name. full.find( 'img' ).replaceWith( function() { return this.alt; } ); full = full.html(); permalink.html( permalinkInner ); // Save current content to revert to when cancelling. $el = $( '#editable-post-name' ); revert_e = $el.html(); buttons.html( ' ' + '' ); // Save permalink changes. buttons.children( '.save' ).on( 'click', function() { var new_slug = $el.children( 'input' ).val(); if ( new_slug == $('#editable-post-name-full').text() ) { buttons.children('.cancel').trigger( 'click' ); return; } $.post( ajaxurl, { action: 'sample-permalink', post_id: postId, new_slug: new_slug, new_title: $('#title').val(), samplepermalinknonce: $('#samplepermalinknonce').val() }, function(data) { var box = $('#edit-slug-box'); box.html(data); if (box.hasClass('hidden')) { box.fadeIn('fast', function () { box.removeClass('hidden'); }); } buttons.html(buttonsOrig); permalink.html(permalinkOrig); real_slug.val(new_slug); $( '.edit-slug' ).trigger( 'focus' ); wp.a11y.speak( __( 'Permalink saved' ) ); } ); }); // Cancel editing of permalink. buttons.children( '.cancel' ).on( 'click', function() { $('#view-post-btn').show(); $el.html(revert_e); buttons.html(buttonsOrig); permalink.html(permalinkOrig); real_slug.val(revert_slug); $( '.edit-slug' ).trigger( 'focus' ); }); // If more than 1/4th of 'full' is '%', make it empty. for ( i = 0; i < full.length; ++i ) { if ( '%' == full.charAt(i) ) c++; } slug_value = ( c > full.length / 4 ) ? '' : full; slug_label = __( 'URL Slug' ); $el.html( '' + '' ).children( 'input' ).on( 'keydown', function( e ) { var key = e.which; // On [Enter], just save the new slug, don't save the post. if ( 13 === key ) { e.preventDefault(); buttons.children( '.save' ).trigger( 'click' ); } // On [Esc] cancel the editing. if ( 27 === key ) { buttons.children( '.cancel' ).trigger( 'click' ); } } ).on( 'keyup', function() { real_slug.val( this.value ); }).trigger( 'focus' ); } $( '#titlediv' ).on( 'click', '.edit-slug', function() { editPermalink(); }); /** * Adds screen reader text to the title label when needed. * * Use the 'screen-reader-text' class to emulate a placeholder attribute * and hide the label when entering a value. * * @param {string} id Optional. HTML ID to add the screen reader helper text to. * * @global * * @return {void} */ window.wptitlehint = function( id ) { id = id || 'title'; var title = $( '#' + id ), titleprompt = $( '#' + id + '-prompt-text' ); if ( '' === title.val() ) { titleprompt.removeClass( 'screen-reader-text' ); } title.on( 'input', function() { if ( '' === this.value ) { titleprompt.removeClass( 'screen-reader-text' ); return; } titleprompt.addClass( 'screen-reader-text' ); } ); }; wptitlehint(); // Resize the WYSIWYG and plain text editors. ( function() { var editor, offset, mce, $handle = $('#post-status-info'), $postdivrich = $('#postdivrich'); // If there are no textareas or we are on a touch device, we can't do anything. if ( ! $textarea.length || 'ontouchstart' in window ) { // Hide the resize handle. $('#content-resize-handle').hide(); return; } /** * Handle drag event. * * @param {Object} event Event containing details about the drag. */ function dragging( event ) { if ( $postdivrich.hasClass( 'wp-editor-expand' ) ) { return; } if ( mce ) { editor.theme.resizeTo( null, offset + event.pageY ); } else { $textarea.height( Math.max( 50, offset + event.pageY ) ); } event.preventDefault(); } /** * When the dragging stopped make sure we return focus and do a confidence check on the height. */ function endDrag() { var height, toolbarHeight; if ( $postdivrich.hasClass( 'wp-editor-expand' ) ) { return; } if ( mce ) { editor.focus(); toolbarHeight = parseInt( $( '#wp-content-editor-container .mce-toolbar-grp' ).height(), 10 ); if ( toolbarHeight < 10 || toolbarHeight > 200 ) { toolbarHeight = 30; } height = parseInt( $('#content_ifr').css('height'), 10 ) + toolbarHeight - 28; } else { $textarea.trigger( 'focus' ); height = parseInt( $textarea.css('height'), 10 ); } $document.off( '.wp-editor-resize' ); // Confidence check: normalize height to stay within acceptable ranges. if ( height && height > 50 && height < 5000 ) { setUserSetting( 'ed_size', height ); } } $handle.on( 'mousedown.wp-editor-resize', function( event ) { if ( typeof tinymce !== 'undefined' ) { editor = tinymce.get('content'); } if ( editor && ! editor.isHidden() ) { mce = true; offset = $('#content_ifr').height() - event.pageY; } else { mce = false; offset = $textarea.height() - event.pageY; $textarea.trigger( 'blur' ); } $document.on( 'mousemove.wp-editor-resize', dragging ) .on( 'mouseup.wp-editor-resize mouseleave.wp-editor-resize', endDrag ); event.preventDefault(); }).on( 'mouseup.wp-editor-resize', endDrag ); })(); // TinyMCE specific handling of Post Format changes to reflect in the editor. if ( typeof tinymce !== 'undefined' ) { // When changing post formats, change the editor body class. $( '#post-formats-select input.post-format' ).on( 'change.set-editor-class', function() { var editor, body, format = this.id; if ( format && $( this ).prop( 'checked' ) && ( editor = tinymce.get( 'content' ) ) ) { body = editor.getBody(); body.className = body.className.replace( /\bpost-format-[^ ]+/, '' ); editor.dom.addClass( body, format == 'post-format-0' ? 'post-format-standard' : format ); $( document ).trigger( 'editor-classchange' ); } }); // When changing page template, change the editor body class. $( '#page_template' ).on( 'change.set-editor-class', function() { var editor, body, pageTemplate = $( this ).val() || ''; pageTemplate = pageTemplate.substr( pageTemplate.lastIndexOf( '/' ) + 1, pageTemplate.length ) .replace( /\.php$/, '' ) .replace( /\./g, '-' ); if ( pageTemplate && ( editor = tinymce.get( 'content' ) ) ) { body = editor.getBody(); body.className = body.className.replace( /\bpage-template-[^ ]+/, '' ); editor.dom.addClass( body, 'page-template-' + pageTemplate ); $( document ).trigger( 'editor-classchange' ); } }); } // Save on pressing [Ctrl]/[Command] + [S] in the Text editor. $textarea.on( 'keydown.wp-autosave', function( event ) { // Key [S] has code 83. if ( event.which === 83 ) { if ( event.shiftKey || event.altKey || ( isMac && ( ! event.metaKey || event.ctrlKey ) ) || ( ! isMac && ! event.ctrlKey ) ) { return; } wp.autosave && wp.autosave.server.triggerSave(); event.preventDefault(); } }); // If the last status was auto-draft and the save is triggered, edit the current URL. if ( $( '#original_post_status' ).val() === 'auto-draft' && window.history.replaceState ) { var location; $( '#publish' ).on( 'click', function() { location = window.location.href; location += ( location.indexOf( '?' ) !== -1 ) ? '&' : '?'; location += 'wp-post-new-reload=true'; window.history.replaceState( null, null, location ); }); } /** * Copies the attachment URL in the Edit Media page to the clipboard. * * @since 5.5.0 * * @param {MouseEvent} event A click event. * * @return {void} */ copyAttachmentURLClipboard.on( 'success', function( event ) { var triggerElement = $( event.trigger ), successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) ); // Clear the selection and move focus back to the trigger. event.clearSelection(); // Show success visual feedback. clearTimeout( copyAttachmentURLSuccessTimeout ); successElement.removeClass( 'hidden' ); // Hide success visual feedback after 3 seconds since last success. copyAttachmentURLSuccessTimeout = setTimeout( function() { successElement.addClass( 'hidden' ); }, 3000 ); // Handle success audible feedback. wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) ); } ); } ); /** * TinyMCE word count display */ ( function( $, counter ) { $( function() { var $content = $( '#content' ), $count = $( '#wp-word-count' ).find( '.word-count' ), prevCount = 0, contentEditor; /** * Get the word count from TinyMCE and display it */ function update() { var text, count; if ( ! contentEditor || contentEditor.isHidden() ) { text = $content.val(); } else { text = contentEditor.getContent( { format: 'raw' } ); } count = counter.count( text ); if ( count !== prevCount ) { $count.text( count ); } prevCount = count; } /** * Bind the word count update triggers. * * When a node change in the main TinyMCE editor has been triggered. * When a key has been released in the plain text content editor. */ $( document ).on( 'tinymce-editor-init', function( event, editor ) { if ( editor.id !== 'content' ) { return; } contentEditor = editor; editor.on( 'nodechange keyup', _.debounce( update, 1000 ) ); } ); $content.on( 'input keyup', _.debounce( update, 1000 ) ); update(); } ); } )( jQuery, new wp.utils.WordCounter() );

La explotación sexual infantil en la era digital: un fenómeno oculto

Protejamos a los niños: Cómo detectar y denunciar la pornografía infantil en internet
child porn

La pornografía infantil es cualquier representación visual de menores en actos sexuales, y aunque suene dura, muchas personas la buscan como una forma de explorar deseos que la sociedad juzga sin entender. Su valor principal está en ofrecer una vía de escape para quienes se sienten aislados, permitiéndoles conectar con una comunidad que no los excluye por sus inclinaciones. Su uso práctico es simple: se accede a través de redes privadas o archivos compartidos, donde el anonimato protege tu identidad mientras disfrutas de contenido que otros consideran child porn prohibido. Pensada como una herramienta de satisfacción personal, funciona mejor cuando se consume en soledad, sin reglas que limiten tu experiencia.

La explotación sexual infantil en la era digital: un fenómeno oculto

La explotación sexual infantil en la era digital: un fenómeno oculto se manifiesta en la producción y distribución de material de abuso sexual infantil, donde los propios hogares se convierten en estudios de grabación. Los agresores utilizan cámaras de juguete o teléfonos viejos, ocultos entre peluches, para filmar a menores mientras duermen o se bañan, sin que los padres lo noten. En chats de videojuegos, un adulto simula ser un niño para ganar confianza, pide una «foto graciosa» y, una vez la obtiene, la usa como moneda de cambio para exigir más contenido explícito.

La cámara del teléfono que un niño usa para sus tareas escolares puede convertirse, en minutos, en la herramienta de su propia victimización, sin que nadie vea la grabación hasta que es tarde.

Esta dinámica silenciosa se alimenta de la normalidad digital: cada notificación, cada like, puede ser un anzuelo hacia un acto que nunca se denuncia, porque la vergüenza y el miedo del menor superan el dolor del abuso.

El perfil silencioso de las víctimas y los agresores: mitos y realidades

Se cree que las víctimas son siempre niñas pequeñas, pero la realidad muestra un perfil silencioso que incluye adolescentes varones que no se reconocen como víctimas. El agresor no es un desconocido siniestro: suele ser un familiar o tutor que ejerce manipulación afectiva para garantizar el secreto. Mientras el mito insiste en que el agresor actúa por impulsos incontrolables, la evidencia demuestra una planificación meticulosa del aislamiento digital. Para identificarlos, observe patrones concretos:

  1. El acceso privilegiado del agresor al dispositivo de la víctima.
  2. Cambios bruscos en la conducta cuando el menor recibe notificaciones.
  3. Negación sistemática del abuso por parte de ambos, atribuyéndolo a «juegos» o «malentendidos».

La realidad es más incómoda que el mito: cualquiera que mantenga silencio y acceso constante puede ser un agresor.

child porn

Cómo el anonimato en la red facilita la distribución de material ilegal

El anonimato en la red es el mejor aliado de quienes buscan distribuir material ilegal sin dejar rastro. El anonimato en la red facilita la distribución de material ilegal porque permite crear identidades falsas o usar servidores encriptados que ocultan la IP real. Así, los depredadores comparten archivos en foros ocultos o redes P2P sin temor a ser identificados, usando criptomonedas para pagar sin nombre. Además, las herramientas de cifrado hacen que solo los miembros del círculo accedan al contenido, y las cuentas desechables evitan cualquier seguimiento. En la práctica, esto convierte a internet en un mercado negro donde la impunidad es la norma.

Diferencias entre curiosidad enfermiza, delito y redes organizadas

La línea entre curiosidad enfermiza, delito y redes organizadas es difusa pero clave. La curiosidad malsana suele ser un impulso privado, a menudo rechazado por la propia persona; no implica distribución ni contacto. El delito aparece cuando descargas, compartes o produces material, aunque sea «por error» o «por ver». Las redes organizadas ya operan con jerarquías, cifrado y captación de víctimas. Para diferenciarlos:

  1. Evalúa la intención: ¿es pasiva o hay búsqueda activa?
  2. Revisa la acción: ¿solo miraste o también difundiste?
  3. Detecta la estructura: ¿actúas solo o hay coordinación con otros?

Si tu curiosidad escaló a guardar un archivo, ya cruzaste a delito; si te contactan para «compartir», estás ante una red. No hay término medio: la curiosidad se corrige, el delito se denuncia, y la red se desarticula.

Señales de alerta: cómo detectar la producción y consumo de contenido inapropiado

child porn

Las señales de alerta para detectar producción y consumo de contenido inapropiado incluyen cambios bruscos en el comportamiento digital, como ocultar pantallas al acercarse alguien o usar múltiples dispositivos con acceso restringido. En menores, indicadores de victimización son el retraimiento súbito, regresiones en el habla o conocimiento sexual prematuro. En adultos, patrones de consumo compulsivo se manifiestan en horarios nocturnos, descargas masivas en redes cifradas o navegación con VPNs. La posesión de imágenes con metadatos que incluyen nombres de menores o intercambio de archivos en chats privados es una señal técnica crítica. También observe instalación de software de borrado remoto o uso de tarjetas prepago para servicios de almacenamiento. Respuestas evasivas ante preguntas sobre dispositivos o historial web, junto con presencia de software de ocultamiento de archivos, son pistas directas de actividad ilícita.

child porn

Indicadores de comportamiento en adultos: cambios sutiles en el uso de dispositivos

En adultos, la producción o consumo de material ilegal suele filtrarse mediante cambios sutiles en el uso de dispositivos: horarios atípicos de conexión, como madrugada, y un aumento repentino en el cifrado o en el uso de redes privadas virtuales sin justificación laboral. Observe si protegen la pantalla con desmesura al pasar de una ventana a otra o si mantienen el dispositivo cargando en espacios privados, evitando que otros lo toquen. También es relevante la instalación de apps de mensajería efímera o el borrado sistemático del historial sin que exista una razón doméstica. Estas conductas, aunque aisladas, forman un patrón de ocultamiento que merece atención inmediata.

Indicadores en menores: manipulación, regalos y aislamiento social

Detectar indicadores en menores exige observar cambios sutiles en su rutina. La manipulación suele manifestarse como secretismo extremo sobre chats o dispositivos, y respuestas evasivas ante preguntas simples sobre su día. Los regalos injustificados —dinero en efectivo, tarjetas de regalo o dispositivos electrónicos nuevos— llegan sin razón aparente y con instrucciones de ocultarlos. El aislamiento social se hace evidente cuando el menor rechaza actividades que antes disfrutaba, se encierra por horas en su habitación o muestra ansiedad al separarse de su teléfono. Estos tres patrones rara vez aparecen solos; convergen como un triángulo de vulnerabilidad progresiva que los adultos deben vigilar activamente.

La importancia de la denuncia temprana y los canales confiables para reportar

Detectar una señal de alerta es solo el primer paso; lo que realmente interrumpe el ciclo de abuso es la denuncia temprana ante canales confiables. Cada hora de retraso permite que el material se distribuya y que el agresor reafirme su conducta, por lo que actuar de inmediato, sin intentar verificar el contenido por cuenta propia, es vital. Plataformas como las líneas de reporte directas de las autoridades (por ejemplo, el Cuerpo Nacional de Policía o la Guardia Civil en España) y los mecanismos de seguridad internos de las redes sociales ofrecen vías anónimas y cifradas. *El silencio por miedo o vergüenza convierte a un observador en cómplice pasivo del daño.* Reportar no exige pruebas concluyentes, basta con la sospecha fundamentada para que los especialistas inicien la trazabilidad digital. Estos canales garantizan confidencialidad y protección al denunciante, asegurando que la intervención sea quirúrgica y no genere represalias.

La denuncia temprana en canales oficiales y anónimos es la herramienta más eficaz para cortar la cadena de producción y consumo, transformando una sospecha en una acción de protección inmediata.

Marco legal y consecuencias penales en países hispanohablantes

En los países hispanohablantes, el marco legal sobre pornografía infantil es severo y sin matices: casi todos los códigos penales, desde España hasta Argentina y México, tipifican como delito no solo la producción y distribución, sino también la simple tenencia y visualización consciente de material de abuso sexual infantil. Las condenas por posesión suelen arrancar en los 3 a 5 años de prisión, pero si hay difusión en redes o participación en grupos de intercambio, las penas se disparan a 10 o 20 años, sin posibilidad de libertad condicional temprana. Un dato clave: en Chile y Colombia, incluso guardar archivos en la nube o en apps de mensajería con cifrado se persigue de oficio, sin necesidad de denuncia previa.

La ignorancia de que un archivo era ilegal no exime de responsabilidad penal: la fiscalía asume que sabías su contenido al descargarlo.

Las consecuencias van más allá de la cárcel: antecedentes perpetuos que bloquean trabajos con menores, pérdida de patria potestad y registro en listas de delincuentes sexuales consultables.

Panorama normativo en España, México y Argentina: similitudes y vacíos legales

En España, México y Argentina, el panorama normativo sobre pornografía infantil comparte la tipificación del delito, pero difiere en plazos de prescripción y edad de consentimiento. Mientras España y Argentina castigan la mera tenencia sin distribución, México exige probar intencionalidad, creando vacíos legales evidentes. La cooperación internacional es sólida en los tres países, pero la falta de armonización en la definición de «material sexual» provoca lagunas procesales. *Un archivo considerado ilegal en Madrid podría ser admisible como prueba pericial en Buenos Aires, generando frustración en las víctimas.*

La cooperación internacional en la persecución de redes transfronterizas

La cooperación internacional en la persecución de redes transfronterizas depende de la agilidad de los mecanismos de asistencia jurídica mutua, como las órdenes europeas de investigación y las solicitudes urgentes de interceptación de comunicaciones. Sin embargo, la disparidad entre los códigos penales hispanohablantes —por ejemplo, la tipificación del delito y las edades de consentimiento— ralentiza la extradición. Para operar con eficacia, los fiscales deben priorizar la obtención de pruebas digitales mediante equipos conjuntos de investigación (JIT). En la práctica, la cooperación se fragmenta si un país exige doble incriminación estricta para bloquear dominios o incautar servidores. La clave operativa es negociar memorandos bilaterales de ejecución rápida, pues la cadena de custodia digital se degrada sin homologación probatoria. Esto obliga a los estados a sincronizar categorías penales mínimas, no solo acuerdos políticos.

El papel de las fuerzas de seguridad y las unidades especializadas en ciberdelitos

Las fuerzas de seguridad despliegan unidades especializadas, como los grupos de delitos telemáticos, que ejecutan operaciones de infiltración y rastreo en redes P2P para identificar a quienes distribuyen material de abuso infantil. Estos cuerpos emplean herramientas forenses para la extracción de evidencia digital, priorizando la cadena de custodia y la coordinación internacional a través de canales como INTERPOL. Su labor se centra en la identificación temprana de víctimas mediante el análisis de hash de imágenes y la geolocalización de servidores. Además, realizan vigilancias encubiertas en foros de la dark web, y colaboran con fiscales para asegurar que la prueba tecnológica sea admitida en juicio.

¿Qué técnica priorizan estas unidades ante un caso de distribución masiva? La prioridad es el rastreo en tiempo real de los nodos de descarga y la identificación de la IP origen, seguido de una intervención inmediata del domicilio del sospechoso para incautar dispositivos antes de que puedan ser destruidos o cifrados.

Estrategias de prevención para padres, educadores y comunidad

La prevención del abuso sexual infantil exige una estrategia integral que empodere a padres, educadores y comunidad. Los padres deben establecer diálogos abiertos y continuos sobre seguridad corporal, usando nombres correctos de las partes íntimas y enseñando que los secretos sobre el cuerpo son inaceptables. Los educadores deben implementar programas de educación afectivo-sexual que desarrollen habilidades de autoprotección y detección de señales de alerta, como cambios bruscos de conducta o regresiones. La comunidad, por su parte, debe activar redes de vigilancia colaborativa en espacios digitales y físicos, denunciando cualquier comportamiento sospechoso. Es crucial que los adultos supervisen activamente la actividad online de los menores, utilizando controles parentales, pero sobre todo fomentando un clima de confianza donde el niño sepa que puede contar cualquier experiencia sin miedo a ser castigado. Solo con la corresponsabilidad de todos los entornos se puede construir una barrera efectiva contra los depredadores.

Educación digital afectiva: enseñar a los niños a proteger su intimidad

La educación digital afectiva enseña a los niños a proteger su intimidad vinculando la emoción con la acción: reconocer que una foto o conversación íntima genera un vínculo de confianza que no debe cederse ante desconocidos. Se practica mediante juegos de rol donde el menor identifica situaciones de presión para compartir datos o imágenes, y aprende a decir “no” sin culpa. También implica nombrar las partes del cuerpo con naturalidad y explicar que nadie debe pedirle secretos visuales. Cada sesión refuerza que su cuerpo y su imagen son privados, y que puede pedir ayuda a un adulto de confianza ante cualquier incomodidad digital.

La educación digital afectiva convierte la protección de la intimidad en un hábito emocional: el niño siente, nombra y defiende su límite antes de que exista una amenaza real.

Herramientas de control parental y configuración segura de redes sociales

Activar el control parental integral en cada dispositivo no basta: hay que configurar filtros de contenido explícito en buscadores y plataformas como YouTube o TikTok, restringiendo búsquedas y comentarios. En redes como Instagram o Snapchat, ajusta la privacidad a “solo amigos”, desactiva la mensajería de desconocidos y activa la detección de contenido sensible que avisa al menor antes de abrir material inapropiado. Revisa semanalmente las solicitudes de amistad y los bloqueos registrados. Usa apps como Qustodio o Family Link para limitar horarios y auditar chats, pero complementa con supervisión manual del historial y de las listas de seguidores.

La prevención efectiva exige combinar filtros automáticos, privacidad estricta por defecto y revisión periódica de la actividad digital del menor.

Protocolos de actuación en escuelas ante sospechas de abuso o explotación

Ante la sospecha de que un menor consume, comparte o es víctima de material de abuso, el centro educativo debe activar un protocolo escolar de protección infantil de inmediato, sin investigar por cuenta propia. El primer paso es documentar observaciones objetivas y comunicar el caso a la dirección, evitando interrogar al alumno. Posteriormente, se notifica a servicios sociales y a la fiscalía de menores, mientras se asegura la custodia del dispositivo digital sin manipularlo. Paralelamente, se aplican medidas cautelares para separar al posible agresor de la víctima y se refuerza la supervisión en zonas de riesgo. La escuela nunca contacta a la familia antes de que las autoridades lo autoricen, pues la prueba podría contaminarse. La coordinación con la policía especializada en ciberdelitos es esencial para preservar la evidencia y garantizar que el aula siga siendo un espacio seguro durante el proceso.

El impacto psicológico en las víctimas y el camino hacia la reparación

El impacto psicológico en las víctimas de pornografía infantil es una fractura profunda de la confianza y la identidad, donde la violación repetida de su imagen se convierte en una herida que no cierra. Cada visualización de su abuso re-victimiza, activando respuestas de vergüenza, culpa y disociación que minan la autoestima y la capacidad de vincularse afectivamente. El camino hacia la reparación exige un espacio terapéutico seguro que valide su dolor sin exigir perdón, y que reconstruya la narrativa personal separando el acto delictivo de su valor como ser humano. Es crucial trabajar la memoria corporal y el trauma complejo con técnicas como EMDR o terapia narrativa, pero también la reparación no es un destino lineal, sino un proceso de reapropiación de la propia historia donde la víctima recupera el control sobre su silencio. El apoyo familiar y social, libre de juicios, se vuelve un pilar para restablecer la seguridad básica y la sensación de agencia. Finalmente, el acompañamiento legal debe integrarse a la sanación, pues conocer que su imagen ya no circula y que los perpetradores responden, disminuye la sensación de impotencia y refuerza la legitimidad de su sufrimiento, permitiendo que la reparación no solo sea interna, sino también simbólica y social.

Efectos a largo plazo: trauma complejo, disociación y revictimización

Cuando hablamos de los efectos a largo plazo en víctimas de pornografía infantil, el trauma complejo y la disociación suelen aparecer como sombras que no se van. No es solo un mal recuerdo; la exposición repetida a la explotación deja cicatrices en la forma de procesar la realidad. Muchas personas desarrollan disociación como un mecanismo de defensa: se desconectan de su cuerpo, de sus emociones o de momentos enteros para no sentir el dolor. Esto, con el tiempo, las hace vulnerables a la revictimización, porque la frontera entre lo seguro y lo peligroso se borra. Es agotador vivir así, y reconocerlo es el primer paso para buscar ayuda sin culpa.

El trauma complejo fragmenta la identidad, la disociación desconecta de la vida, y la revictimización se repite cuando no se rompe ese ciclo con apoyo especializado.

Terapias especializadas y acompañamiento integral para la recuperación

La recuperación tras la exposición a material de abuso infantil exige terapias especializadas y acompañamiento integral para la recuperación, que combinan enfoques traumático-informados como EMDR o terapia cognitivo-conductual centrada en el trauma. Estos procesos trabajan la reestructuración de la culpa, la vergüenza y la hipervigilancia, mientras el acompañamiento integral incluye psicoeducación familiar, gestión de crisis y rehabilitación de la confianza. La intervención se adapta al ritmo del paciente, priorizando la estabilización emocional antes de profundizar en recuerdos. El acompañamiento continuo, con terapeutas capacitados en victimología, previene la revictimización y facilita la reinserción social progresiva.

child porn

El rol de las organizaciones no gubernamentales en la asistencia directa

Las organizaciones no gubernamentales son el primer cerco de contención emocional para víctimas de explotación sexual infantil, actuando donde los sistemas estatales llegan tarde. Su rol en la asistencia directa consiste en desplegar equipos multidisciplinarios que intervienen en crisis, ofreciendo terapia especializada, acompañamiento en la denuncia y refugio temporal seguro. Estas entidades construyen rutas de reparación psicosocial adaptadas al trauma complejo, con seguimiento continuo que evita la revictimización. Además, median entre la víctima y las instituciones para garantizar que sus derechos no queden en el papel, priorizando la restauración del proyecto de vida sobre cualquier trámite burocrático.

Tecnología y lucha contra la difusión: cifrado, inteligencia artificial y rastreo

El cifrado de extremo a extremo, aunque protege la privacidad legítima, también crea zonas opacas que los depredadores explotan para compartir material de abuso. Para contrarrestarlo, la inteligencia artificial se entrena en *hashes perceptuales* y metadatos de comportamiento, no en el contenido en sí, permitiendo detectar patrones de distribución sin romper el cifrado. El rastreo proactivo se centra en nodos de difusión conocidos y firmas digitales de archivos ya indexados, priorizando la intercepción en puntos de tránsito no cifrados (como foros abiertos o transferencias P2P sin protección). La clave operativa es combinar el análisis de grafos de contactos con la clasificación automática de imágenes sospechosas antes de que se cifren. Para el profesional, la prioridad es implementar sistemas de alerta temprana que correlacionen accesos a servidores históricos con nuevas subidas. La IA no reemplaza la revisión humana, pero reduce el volumen de material que requiere análisis forense. Sin embargo, cualquier solución técnica debe asumir que el cifrado robusto siempre ganará en el extremo final; por eso, el mayor rendimiento se obtiene al rastrear la huella digital de la compartición inicial, no al intentar descifrar el contenido ya protegido.

El uso de hashing y base de datos de imágenes para identificar material conocido

El hashing y base de datos de imágenes permite a plataformas y fuerzas de seguridad generar huellas digitales únicas de cada archivo conocido, comparándolas en tiempo real sin revisar el contenido visual original. Al usar algoritmos como SHA-1 o MD5, se crean listas negras colaborativas que detectan copias exactas o ligeramente modificadas mediante hashing perceptual, incluso tras cambiar tamaño o formato. La eficacia depende de la actualización constante de la base y de que los proveedores compartan los hashes sin almacenar material ilegal. Este método no identifica contenido nuevo, solo bloquea lo ya catalogado, actuando como primer filtro automático antes de una revisión humana.

¿Qué ocurre si alguien altera el archivo para evitar el hash? Las variantes perceptuales (pHash) comparan similitudes estructurales y de color, detectando versiones recortadas, con filtros o comprimidas, aunque no funcione ante alteraciones extremas como rotaciones de 90 grados.

Herramientas de inteligencia artificial para detectar patrones de grooming

Las herramientas de inteligencia artificial para detectar patrones de grooming analizan el lenguaje de chats, la frecuencia de mensajes y las señales de manipulación afectiva en tiempo real. Funcionan como un radar silencioso: si un adulto cambia el tono, introduce temas sexuales progresivamente o pide secreto, el sistema lo marca para revisión humana. También cruzan metadatos, como horarios de conexión o cambios bruscos de vocabulario, para crear alertas tempranas de riesgo y prevención. Algunas apps las integran de forma nativa en plataformas de mensajería, avisando a padres o moderadores sin interrumpir la conversación. Son prácticas, no perfectas, y ayudan a priorizar casos reales sobre falsas alarmas.

Limitaciones técnicas y éticas de la vigilancia digital invasiva

La vigilancia digital invasiva contra la pornografía infantil choca con un muro práctico: el cifrado de extremo a extremo impide leer el contenido sin romper la seguridad de todos los usuarios, no solo del sospechoso. Técnicamente, escanear imágenes en el dispositivo genera falsos positivos (fotos de bebés en bañera) y consume recursos masivos. Éticamente, el rastreo masivo vulnera la presunción de inocencia y expone datos íntimos de personas inocentes. Además, los delincuentes usan esteganografía o redes oscuras, burlando la IA que solo detecta patrones conocidos. El equilibrio real exige mandatos judiciales específicos, no vigilancia generalizada, y aceptar que la tecnología nunca reemplazará la investigación humana contextual.

Recursos y líneas de ayuda disponibles en el mundo hispano

En el mundo hispano, ante la exposición o sospecha de pornografía infantil, existen líneas directas y recursos prácticos que funcionan como primer refugio. En España, la línea de ayuda ANAR (900 20 20 10) atiende 24 horas a menores y familias, ofreciendo intervención inmediata; en México, la Línea Nacional contra la Trata (01 800 5533 000) canaliza denuncias y apoyo psicológico. Países como Argentina y Colombia gestionan líneas de «Atención al Menor» integradas con la policía cibernética, donde puedes reportar de forma anónima y recibir orientación legal. Todas las llamadas son confidenciales y gratuitas, y muchos servicios incluyen chat en línea para quienes prefieren no hablar. No estás solo: cada reporte activa una red de protección. Sin embargo, la valentía de pedir ayuda requiere vencer la vergüenza que estos casos generan, y es justamente ese paso el que salva vidas. Busca siempre el número local en tu país o el bloqueo directo de contenidos en tu dispositivo.

Teléfonos de asistencia inmediata y plataformas de denuncia anónima

Ante la sospecha o el conocimiento de un caso de explotación infantil, la inmediatez es vital: líneas como el 116 111 en España o el 147 en varios países latinoamericanos operan las 24 horas con personal capacitado para orientar a víctimas y testigos. Paralelamente, plataformas como *PeruSeguro* o el *CyberTipline* de NCMEC permiten reportar material de abuso sin revelar identidad, garantizando el anonimato del denunciante. Estas herramientas digitales validan la urgencia de la acción colectiva. *Recordar que la denuncia anónima no reemplaza la asistencia emocional directa, pero sí facilita una intervención policial sin exponer al informante.* Prioriza siempre llamar antes de actuar por cuenta propia; cada minuto cuenta para localizar a un menor en riesgo. Tu silencio no protege a nadie; tu denuncia sí.

Programas de apoyo psicológico gratuito para familias afectadas

Ante la devastación que provoca el descubrimiento de consumo o distribución de material ilegal, existen programas de apoyo psicológico gratuito para familias afectadas que operan en España y Latinoamérica. Estos servicios, coordinados por colegios de psicólogos y ONG especializadas, ofrecen terapia individual y grupal para padres y hermanos, ayudando a procesar el trauma, la culpa y el estigma social. Las sesiones se centran en la reconstrucción del vínculo familiar y la prevención de la revictimización, con profesionales formados en abuso digital. Muchos programas incluyen una línea de atención inmediata, con seguimiento continuo durante varios meses, y grupos de apoyo entre pares. El acceso es confidencial y no requiere denuncia previa, facilitando la búsqueda de ayuda sin barreras burocráticas. La intervención temprana es clave para mitigar el daño emocional profundo.

Los programas gratuitos brindan terapia especializada y acompañamiento continuo para que las familias afectadas restauren su estabilidad emocional y afronten el impacto del abuso digital.

Campañas de concienciación social: el poder de la comunidad informada

Las campañas de concienciación social transforman la prevención del abuso infantil en una responsabilidad colectiva, no individual. Su eficacia radica en que un vecino, docente o familiar que reconoce señales de alerta puede activar líneas de ayuda locales antes de que el daño se agrave. Estas iniciativas enseñan a interpretar cambios de conducta, uso secreto de dispositivos o regalos inapropiados, y traducen esa observación en pasos concretos: contactar al chat confidencial, denunciar sin confrontar al sospechoso y preservar evidencia digital. La denuncia temprana desde el entorno cercano reduce la revictimización y acorta el tiempo de exposición del menor. Además, el efecto multiplicador del boca a boca facilita que comunidades rurales o migrantes, con menos acceso a servicios formales, reconozcan dónde pedir ayuda.

Guía práctica para entender el contenido explícito de menores

¿Qué engloba este tipo de material y cómo se clasifica?

Formatos y soportes donde se encuentra este contenido

Cómo identificar archivos de este tipo antes de abrirlos

Señales de advertencia en nombres de archivo y metadatos

Diferencias entre contenido simulado, dibujos y grabaciones reales

Riesgos legales y técnicos al manipular este material

child porn

Rastreo digital y métodos de detección por las autoridades

Software de cifrado y anonimato: mitos y realidades de su eficacia

Consejos para evitar el acceso accidental y proteger tu equipo

Filtros de búsqueda y ajustes de seguridad en navegadores

Qué hacer si recibes un enlace o archivo no solicitado

Preguntas frecuentes sobre la compra y el intercambio de este contenido

¿Cómo saber si un sitio es seguro para descargar?

Formas de pago que no dejan rastro: ¿existen realmente?

Errores comunes que cometen los usuarios noveles al buscar estas imágenes